Description
Building off of #49295 (comment), we’re considering a new mode where all of the current places where Node defaults to CommonJS would instead default to ESM. I think this should be enabled by flag, and once it ships we can potentially ship a separate binary where it’s enabled by default; and/or we can someday make the new mode Node’s default in a semver-major change.
The use cases solved by such a mode are (and I’ll edit this comment to update this list as people think of more):
-
I want to write ESM syntax by default without needing to opt into it, such as via
package.json
file or file extension or--input-type=module
. -
I want to write what are typically called shell scripts in ESM JavaScript, where I can have a single extensionless file anywhere on my disk that uses ESM syntax and it doesn’t need a nearby
package.json
file or a symlink or wrapper file in order to run as ESM. -
I want consistency in how the CLI handles references to files; currently
--import
accepts URL strings but the main entry point must be a path string (and therefore can’t be adata:
URL orhttps:
URL, such as to work with--experimental-network-imports
). -
If this mode becomes enabled by default in a future version of Node, when using that version of Node I want to be able to start a new project and write ESM syntax without needing to take any steps to opt into enabling ESM support.
To handle these use cases, the changes that this mode should make are (and likewise I’ll edit this to reflect consensus):
-
When a
.js
file is outside of any definedpackage.json
scope, because there are nopackage.json
files in its folder or any folders above it, it will be treated as ESM JavaScript. -
When a
.js
file is in a package scope where its nearest parentpackage.json
lacks a"type"
field, it will be interpreted per the conditions we establish in Discussion: In an ESM-first mode, how should apackage.json
file with notype
field be handled? #49494: when the package scope is under a folder namednode_modules
, the file will be treated as CommonJS; otherwise it will be treated as ESM. -
When an extensionless file is outside of any defined
package.json
scope, it can be run as an entry point or imported per the conditions we establish in Discussion: In an ESM-first mode, how should extensionless entry points be handled? #49431: if the file begins with the Wasm magic bytes, it will be evaluated as Wasm, and likewise for any other future file types with defined headers that don’t conflict with JavaScript; otherwise it will be evaluated as ESM JavaScript. (Still subject to--experimental-wasm-modules
until that stabilizes.) -
Input from STDIN or
--eval
would be treated as ESM unless--input-type=commonjs
is passed. Or in other words, the default value of--input-type
would flip fromcommonjs
tomodule
. -
The CLI will parse the main entry point as an URL string, similar to how the value of
--import
is parsed.process.argv[1]
will not be parsed by the CommonJS loader.
This new flag will be named per the discussion in #49541.
Prior art: #32394, #49295, #49407
@LiviaMedeiros @nodejs/loaders @nodejs/wasi @nodejs/tsc