Next.js currently forces that the tsconfig.json
file in the source directory has a "module"
configuration value of "esnext"
. This causes any uses of TypeScript that share that tsconfig to generate code that uses import
and export
statements, which are not supported by all tools (such as Node 8).
From my understanding of the module
configuration setting, it only affects TypeScript鈥檚 code generation, which Next does not use (it even forces noEmit
). Rather, Next鈥檚 webpack configuration uses TypeScript for typechecking only and Babel for actual code generation.
Therefore, the value of module
should be irrelevant to Next.js.
Next.js should have no opinion about what the module
setting is.
This is hitting me in a scenario where my Next app shares a root with some scripts written in TypeScript that I run with ts-node
. Because my team鈥檚 environment is Node 8, it errors when it sees the code that was generated to have ES6 modules.
I think the same logic applies to the isolatedModules
setting, which also seems to only affect TypeScript鈥檚 code generation. I鈥檝e had to add import {}
statements in my server code that feel unnecessary.
I鈥檇 argue that noEmit
falls into this bucket as well. That can just be set when Next forks the TypeScript checker, rather than requiring it in the config.
This is hitting me in a scenario where my Next app shares a root with some scripts written in TypeScript that I run with
ts-node
I also had this problem in a small experimental project recently and was able to overcome it by adding an option when calling ts-node
. I'm not referring to this binary directly anyway, so the change I had to make was quite simple:
// package.json
scripts: {
- "exe:dev": "ts-node --transpile-only",
+ "exe:dev": "ts-node --transpile-only --compiler-options=\"{\\\"module\\\": \\\"commonjs\\\"}\"",
}
Example: yarn exe src/commands/fooBar.ts
.
What irritates me a bit though in the new Next.js approach to TypeScript is that hot reloading stops working every time there is a linting problem detected by tsc
(?). I'd just like to transpile whatever possible into JS during development or building; to check code quality I'll use tsc
via yarn lint
when our development process requires so (CI and stuff).
@kachkaev
I also had this problem in a small experimental project recently and was able to overcome it by adding an option when calling
ts-node
.
Another workaround would be to create a separate tsconfig.server.json
file which can be used to compile custom server code, which disables noEmit
and sets module
back to commonjs
specifically when transpiling server code, as demonstrated in the custom-server-typescript example
Yep, those are all useful workarounds. But I would be happier if Next.js didn't require any TypeScript settings it didn't need, and even if it did need them (like --noEmit
) see if they could be moved to Next鈥檚 invocation of tsc
rather than forcing them into the tsconfig.json file itself.
TypeScript will throw an error when it encounters a dynamic export if the module system is not commonjs
or esnext
:
Dynamic import is only supported when '--module' flag is 'commonjs' or 'esNext'.
I'm not convinced that there's a valid use case where a user wants to specify commonjs
despite using Next.js -- this sounds better served by two separate tsconfig.json
s.
I'm OK with removing noEmit
, though.
Would you consider a change that didn鈥檛 overwrite "commonjs" with "esnext" for modules (or perhaps make the "module: esnext" part of the recommended requirements)?
We have some scripts in the same project that we run with ts-node
, which requires commonjs
modules for Node 8. Having a separate tsconfig.json file is an option, of course, but it鈥檚 always nice to avoid that (admittedly slight) complexity.
We probably won't allow it for now -- if more users request this feature we can reconsider it!
@Timer OK. I think we can implement workarounds.
Regardless, thanks for adding in native TypeScript support! This is a huge win for Next and I'm glad that our webapps will be able to adopt it.
My workaround is
ts-node -P another.tsconfig.json somescript.ts
tsc -p another.tsconfig.json
While IMO the best solution would be as @fionawhim suggested:
move (Next.js needed settings) to Next鈥檚 invocation of tsc rather than forcing them into the tsconfig.json file itself.
We should try not to touch user's config as much as possible.
We're also struggling with this.
From a previous setup which was one line in babel.config.js
and a short & sweet tsconfig.json
, we now have two tsconfigs with non-trivial amount of settings in them. We also needed to write docs to explain to our future selves why it's so complicated.
Feels like there's room for improvement for sure 馃槃.
I'm hitting this same problem. In my case, I'm trying to run a custom server that loads Next for some routes and also has an API powered by TypeORM. Unfortunately, TypeORM needs commonjs
modules. It would be really nice if Next did not override tsconfig settings and instead just displayed a warning and what the setting should be. For now, I'm using the compiler options work around:
"start": "ts-node --compiler-options=\"{\\\"module\\\": \\\"commonjs\\\"}\" src/server/main/main.ts",
I'm hitting into this issue too. Using the above workaround.
I am facing the same problem with TypeORM and its whole family of libs. It'd be much better DX if I don't need to set up a custom server only for using some common libraries. I am also not sure if I can still use getServerSideProps
with TypeORM even after having custom server 馃槥
Next.js no longer forces esnext
. You can upgrade Next.js to configure the value.
Most helpful comment
Yep, those are all useful workarounds. But I would be happier if Next.js didn't require any TypeScript settings it didn't need, and even if it did need them (like
--noEmit
) see if they could be moved to Next鈥檚 invocation oftsc
rather than forcing them into the tsconfig.json file itself.