graphql-nexus / nexus

Code-First, Type-Safe, GraphQL Schema Construction
https://nexusjs.org
MIT License
3.4k stars 275 forks source link

How to avoid TypeScript errors when using ESM? #1135

Closed JoosepAlviste closed 2 years ago

JoosepAlviste commented 2 years ago

Hi! I'm trying to convert my project to use native ES modules, but am running into some issues with the type generation from this library.

The main things I changed were that I added "type": "module" to my package.json and "module": "NodeNext" to my tsconfig.json.

The imports in the generated file do not include the file extension, so TypeScript build fails because of this. Here's how the imports in my generated file look like, for example:

import type { Context } from "./../context"
import type { FieldAuthorizeResolver } from "nexus/dist/plugins/fieldAuthorizePlugin"

And here are the errors when running tsc:

error TS2835: Relative import paths need explicit file extensions in EcmaScript imports when '--moduleResolution' is 'node16' or 'nodenext'. Did you mean './../context.js'?

error TS2307: Cannot find module 'nexus/dist/plugins/fieldAuthorizePlugin' or its corresponding type declarations.

Is there some config value I can turn on to make the imports ESM compatible? Or something to ignore the TypeScript errors? I looked through the docs, but couldn't find much.

Would appreciate any help, thanks!

lmiller1990 commented 2 years ago

Note that you can set either NodeNext or esnext, and they are quite different. I think you probably want esnext. NodeNext implemented ES Modules by the spec, which means you must have file extensions (like .js, as the error suggests. You could try adding .js to the imports as suggested - this is actually valid, and TypeScript supports this (when using NodeNext) but you will likely run into more problems.

I'd recommend going with esnext for now, if your goal is simply to use native ESM.

JoosepAlviste commented 2 years ago

Thanks for the tips, I think I got it working!

For future reference, I did the following:

It feels like there could be a simpler way to go about this though, maybe there could be a way to configure if the generated file should include the extensions or not?

In any case, it seems to work for me, so I'll close the issue as solved. Thanks again for the help!

lmiller1990 commented 2 years ago

Change the makeSchema outputs.typegen option extension from .ts to .cts. It looks like we need to keep this file as a CommonJS module for now. Otherwise, I got an error about the extension being missing I mentioned above when running the built production build.

I think that is just a warning, not a fatal error - I've seen this too, I just ignore it - everything still works fine.

Nice summary of your solution :+1:

matus-sabo commented 2 years ago

You can create two files your-name.js.ts and your-name.ts, your-name.ts just reexports content of your-name.js.ts, put file your-name.js.ts into makeSchema, that will result to generated import as your-name.js

idoob commented 1 year ago

You can create two files your-name.js.ts and your-name.ts, your-name.ts just reexports content of your-name.js.ts, put file your-name.js.ts into makeSchema, that will result to generated import as your-name.js

Thanks! It's not a pretty solution but this worked for me! I am using apollo server 4 with nexus with ESM. My specific issue was that I was trying to set the contextType value in makeSchema and was getting same TS error as above. So I created a context.ts file with my type context type definition and another file named context.js.ts that just re-exports the context type.

matus-sabo commented 1 year ago

You can create two files your-name.js.ts and your-name.ts, your-name.ts just reexports content of your-name.js.ts, put file your-name.js.ts into makeSchema, that will result to generated import as your-name.js

Thanks! It's not a pretty solution but this worked for me! I am using apollo server 4 with nexus with ESM. My specific issue was that I was trying to set the contextType value in makeSchema and was getting same TS error as above. So I created a context.ts file with my type context type definition and another file named context.js.ts that just re-exports the context type.

I would recommend switch to pothos

Definitely better developer experience than nexus

lmiller1990 commented 1 year ago

Thanks for the tip, I'll check out Pothos. We definitely won't switch internally, Nexus is doing it's job, but always good to explore new literature for future projects.