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: