Skip to content

Proposal: Detect ESM syntax in every ambiguous file #50064

@GeoffreyBooth

Description

@GeoffreyBooth

Building off of #50043 (comment), this is an alternate proposal to #50043. This aims to achieve the same goals of allowing ESM syntax in “loose” files, where there are no package.json files present; and in files whose nearest parent package.json lacks a type field. This would permit ESM syntax without needing to opt in, while avoiding breaking existing scripts and tutorials. Like #50043, this proposal would avoid any breaking changes, and the aim is to eventually make this enabled by default without requiring a flag.

The new behavior would be as follows:

  • Node would attempt to evaluate every ambiguous file (a file with no explicit .mjs or .cjs extension, either no package.json or one that lacks a type field) as CommonJS, as it already does today. If a file throws a SyntaxError for something that is only allowed in ES modules (import or export statement, import.meta, top-level await), Node would try again to evaluate the file as an ES module.
  • This behavior would apply to ambiguous files within node_modules.
  • This would apply to the main entry point and to files referenced via import. It would not apply to files referenced via require.
  • This behavior would be disabled by any marker of explicitness: .mjs or .cjs extension, a package.json type field, --input-type or --experimental-default-type.

Pros, in comparison with #50043:

  • Avoids the application behaving differently based on entry point: you can reference the entry point from a wrapper, such as a CommonJS test runner, and it will still run as ESM.
  • Prevents the “package author published ambiguous ESM” problem. If a package author develops locally in this mode, relying on it to enable ESM for ambiguous files, their package would still work for consumers.
  • This “per file” approach is the same as that taken by many other tools.

Cons:

  • Presumably this is more of a performance impact, as we’re parsing every ambiguous ES module twice. We should probably measure this to see how much of an impact it is. There should be no impact for CommonJS files, and also no impact for ES modules in an explicit package.json module scope.
  • Any files with ambiguous syntax, that could evaluate successfully as either CommonJS or ESM, would be run as CommonJS in this mode. A common example of such a file would be a polyfill that only sets a global variable, without importing or exporting anything.

@nodejs/loaders @nodejs/tsc

Metadata

Metadata

Assignees

No one assigned

    Labels

    esmIssues and PRs related to the ECMAScript Modules implementation.moduleIssues and PRs related to the module subsystem.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions