Starting with version 8.5.0, Node.js supports ES modules natively, behind a command line option. Most of the credit for this new functionality goes to Bradley Farias.
This blog post explains the details.
The demo repository has the following structure:
esm-demo/
lib.mjs
main.mjs
lib.mjs
:
export function add(x, y) {
return x + y;
}
main.mjs
:
import {add} from './lib.mjs';
console.log('Result: '+add(2, 3));
Running the demo:
$ node --experimental-modules main.mjs
Result: 5
Module specifiers of ES modules:
.mjs
. That way, specifiers remain compatible with the web. If you omit the extension, path resolution works similarly to CJS modules; if the same file exists as both .mjs
and .js
, the former wins.
'../util/tools.mjs'
'lodash'
Features of ES modules:
No dynamic importing of modules. But the dynamic import()
operator is being worked on and should be available relatively soon.
No metavariables such as __dirname
and __filename
. However, there is a proposal to bring similar functionality to ES modules – “import.meta
” by Domenic Denicola:
console.log(import.meta.url);
Interoperability with CJS modules:
ES modules can import CJS modules, but they always only have a default export – the value of module.exports
. Letting a CJS module make named exports (e.g. via a pragma at the beginning of the file) is on the roadmap, but may take a while. If you can help, please do so.
import fs1 from 'fs';
console.log(Object.keys(fs1).length); // 86
import * as fs2 from 'fs';
console.log(Object.keys(fs2)); // ['default']
You can’t use require()
inside ES modules. The main reasons for this are:
NODE_PATH
and require.extensions
. And its specifiers always being URLs also leads to a few minor differences.require()
.await
in ES modules (a feature that is currently under consideration).CJS modules can’t require()
ES modules. Similarly to what was mentioned in the previous item, synchronously loading asynchronous modules is problematic. You’ll probably be able to use the Promise-based import()
operator to load ES modules, though.
If you want to use ES modules on Node.js versions prior to 8.5.0, take a look at @std/esm
by John-David Dalton.
Tip: if you don’t switch on any of the unlockables (extra features), you’ll stay 100% compatible with native ES modules on Node.js.
The current plan is to make ES modules available by default in Node.js 10 LTS.
.mjs
files work with browsers? They do, but they have to be served with the correct Media Type (text/javascript
or application/javascript
). Work on standardizing .mjs
and upgrading tools and libraries is ongoing.
.mjs
required for ES modules? Yes it is – on Node.js. Browsers don’t care about file extensions, only about Media Types (see previous question).
.mjs
required on Node.js? Node.js has to be able to detect whether a file contains a CJS module or an ES module. Several alternatives were considered before one of them was chosen. You can read about the alternatives in a separate blog post. Each one has pros and cons. In my opinion, .mjs
was the right choice (but you can make up your own mind if you read the linked blog post).
More information on ES modules in Node.js and browsers:
.mjs
? How are module specifiers resolved? Etc.]Upcoming ECMAScript proposals: