Skip to content

esm: `--experimental-default-type` flag to flip module defaults

This PR contains work by @LiviaMedeiros, @JakobJingleheimer, @bmeck adapted from #49531, #49540, #49295, #41552, #31388.

This PR implements most of the proposal in #49432. It creates a new flag, --experimental-default-type, which supports values commonjs (the default) or module. Under --experimental-default-type=module, Node.js interprets the following as ES modules:

  • String input provided via --eval or STDIN, if --input-type is unspecified.

  • Files ending in .js or with no extension, if there is no package.json file present in the same folder or any parent folder.

  • Files ending in .js or with no extension, if the nearest parent package.json field lacks a type field; unless the folder is inside a node_modules folder.

Extensionless files are interpreted as Wasm if --experimental-wasm-modules is passed and the file contains the “magic bytes” Wasm header.

The ESM loader is used for all entry points, and we don’t pass through Module.runMain. Under this flag, we no longer support monkey-patching of that method by files loaded via --require.

This PR does not implement the “parse the entry point as a URL” part of #49432, as there are still some design decisions to be made around that and it’s substantial enough to warrant being implemented as a separate PR.

This is related to #49629 and linked PRs, which include the above behaviors for extensionless files but don’t require a flag. I think we can potentially ship that change on its own, separate from making this flag the new default behavior, because extensionless files currently error in module scopes. I’d prefer to ship it behind the --experimental-default-type flag first to work out any kinks before splitting it out to not require any flag.

If people don’t mind, I’d like if this PR thread can focus on the implementation. If anyone has any thoughts on the design or intentions behind this, there’s already a detailed thread for that at #49432.

cc @nodejs/loaders @nodejs/wasi @nodejs/startup @nodejs/tsc

Notable change

The new flag --experimental-default-type can be used to flip the default module system used by Node.js. Input that is already explicitly defined as ES modules or CommonJS, such as by a package.json "type" field or .mjs/.cjs file extension or the --input-type flag, is unaffected. What is currently implicitly CommonJS would instead be interpreted as ES modules under --experimental-default-type=module:

  • String input provided via --eval or STDIN, if --input-type is unspecified.

  • Files ending in .js or with no extension, if there is no package.json file present in the same folder or any parent folder.

  • Files ending in .js or with no extension, if the nearest parent package.json field lacks a type field; unless the folder is inside a node_modules folder.

In addition, extensionless files are interpreted as Wasm if --experimental-wasm-modules is passed and the file contains the “magic bytes” Wasm header.

Merge request reports

Loading