Next.js: TypeScript support unnecessarily forces "esnext" code generation [canary]

Created on 16 May 2019  路  14Comments  路  Source: vercel/next.js

Bug report

Describe the bug

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.

Expected behavior

Next.js should have no opinion about what the module setting is.

System information

  • Version of Next.js: 8.1.1-canary.29

Additional context

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.

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 of tsc rather than forcing them into the tsconfig.json file itself.

All 14 comments

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.jsons.

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.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

nvartolomei picture nvartolomei  路  78Comments

matthewmueller picture matthewmueller  路  102Comments

nickredmark picture nickredmark  路  60Comments

acanimal picture acanimal  路  74Comments

arunoda picture arunoda  路  103Comments