- We assume the current state of the ES module specification. Specifically, we assume that named imports from CommonJS modules cannot be supported.
- The module system should remain as close as possible to Node’s existing module system.
- Developers of portable (node/web) and non-portable (node-only) programs should be given equal priority.
- We should attempt, when possible, to pave the cowpaths established by the JavaScript community.
- A file with the extension
.mjs
is unambiguously an ESM module. - A file with the extension
.js
is ambiguous: it might be an ESM module, a CommonJS module, or a script.
- If the entry file or a file specified using the
--require/-r
flag has import statement or export statements, node will execute the file as ESM. Otherwise it will execute the file as CommonJS.
- The global environment for ESM modules is unchanged.
- The
import.meta
object contains the following properties:url
: A URL string representing the location of the module.filename
: The full path of the currently executing module.dirname
: The directory name of the currently executing module.require
: Allows loading CJS modules.
- There is no change to
node_modules
resolution for bare specifiers. - File extensions are searched as in the current implementation, where
.mjs
is preferred over.js
. - Both
.js
and.mjs
files are loaded as ESM modules. - If the module specifier resolves to a folder, then
- If there is a
package.json
file and that file contains a "main" key, then the package entry point is loaded from that path. - Otherwise, the package entry point is loaded by searching for an
index
file.
- If there is a
You can create a simple ESM entry point at the root of your project:
// Using a default export
export default import.meta.require('./');
// Named exports
export const { exportA, exportB } = import.meta.require('./');
You can use the .mjs
extension for this file.
You can install the esm package to convert ESM modules to CJS modules at runtime:
// Point "package.json::main" here
module.exports = require('esm')(module)('./');
Or you can use Babel to convert ESM to CJS at publish time.
You can have two files side-by-side: one named with a .js
extension and one named with an .mjs
extension. When imported, the .mjs
file will be found. When "required", the .js
file will be found.
import.meta.require('<cjs_module>');
You should also create a PR against the project as well, so that you and others can import it directly.
You can use dynamic import:
// Dynamic import
import('<esm_module>').then(esm => {});
Or you can use esm:
const esm = require('esm')(module)('<esm_module>');
You can use the package.json::module
field, or an index.js
or index.mjs
file.
Work-in-progress