Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

--defaultIsModuleExports and --allowRequireESM #58526

Closed

Conversation

andrewbranch
Copy link
Member

@andrewbranch andrewbranch commented May 13, 2024

Fixes #54102
Alternate to #58480

This splits the behavior of one flag in #58480 into two:

defaultIsModuleExports

Named for the @rollup/plugin-commonjs option, this setting describes the behavior of imports of CommonJS modules in the target runtime/bundler. Note that this flag only takes effect for imports that would, according to emit settings, still be imports in the output JavaScript. It does not affect imports that will be emitted as require statements—that’s what esModuleInterop controls. The available values are:

  • node16/nodenext: The existing behavior in --module node16/nodenext. Imports (in true ESM files) of CommonJS files always come with a synthesized default export; i.e., a default import is module.exports.
  • auto: The existing behavior in all other module modes. Imports of CommonJS files change types based on heuristics related to the presence/absence of __esModule.

Why "node16"/"nodenext" instead of just true? Imagine a default import of a CommonJS module in a .ts file with no package.json. In --module nodenext, that file would emit as a CommonJS .js file, because it lacks any indicator that it’s ESM. Because of that module format detection policy, such an import is not affected by --defaultIsModuleExports—it’s effectively a require. So when --module is nodenext, --defaultIsModuleExports nodenext is equivalent to saying “default imports are always module.exports,” which sounds like true would be a good value for the setting. However, the same import in the same file, under --module preserve, is not effectively a require. It is a real ESM import that exists in a file that is not explicitly marked as ESM. In esbuild, that import behaves like auto (it would conditionally be module.exports or module.exports.default), but if the file were renamed to have a .mts extension or a package.json with "type": "module" were added, it would behave like nodenext (it would always be module.exports). So --defaultIsModuleExports nodenext doesn’t mean “always”; it means “in files that Node.js would recognize as ESM,” which in --module nodenext is all files where the setting could apply, but in --module esnext or --module preserve is a subset of files where the setting could apply. In fewer words:

module file name file format import emits as affected by defaultIsModuleExports
nodenext index.ts CJS require no
nodenext index.mts ESM import yes
preserve index.ts - import yes
preserve index.mts ESM import yes

allowRequireESM

Describes whether require calls are allowed to resolve to ES modules in the target runtime/bundler. The available values are never, always, and node16/nodenext. Again, node16/nodenext has the specific meaning of “requires of files that Node.js would recognize as an ES module.” I thought this was what Webpack does, but I misremembered and may simplify/adjust the option values here.

@typescript-bot
Copy link
Collaborator

Looks like you're introducing a change to the public API surface area. If this includes breaking changes, please document them on our wiki's API Breaking Changes page.

Also, please make sure @DanielRosenwasser and @RyanCavanaugh are aware of the changes, just as a heads up.

@andrewbranch andrewbranch changed the title Feature/54102 alternate --defaultIsModuleExports and --allowRequireESM May 13, 2024
@Jack-Works
Copy link
Contributor

- module: bundler
+ module: { defaultIsModuleExports: true, allowRequireESM: true }

to allow fine-tuning?

@andrewbranch
Copy link
Member Author

module sub-options have been discussed a little; I also have an experiment PR at #56681

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Author: Team For Milestone Bug PRs that fix a bug with a specific milestone
Projects
None yet
Development

Successfully merging this pull request may close these issues.

moduleResolution: bundler diverges from bundlers following node semantics in regards to default import
3 participants