Using native es module in node.js

Time:2019-12-10

Original: using ES modules natively in node.js

By Axel rauschmayer

Starting from version 8.5.0, node.js supports native es modules, which can be turned on through command-line options. Much of the new functionality is due to Bradley Farias.

1. demo

The code directory structure of this example is as follows:

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));

Run Demo:

$ node --experimental-modules main.mjs
Result: 5

2. List: things to pay attention to

ES module:

  • Modules cannot be imported dynamically. But the work on dynamic import () is in progress and should be supported soon.
  • There is no meta variable, such as__dirnameand__filename。 However, there is a proposal for a similar function: “import. Meta”. It might look like this:
console.log(import.meta.url);
  • Now all module identifiers are URLs (this part is new in node.js):

    • File – relative path with file extension:../util/tools.mjs
    • Library – no file extension, no pathlodash
    • How to make NPM library available in browser (without bundler) remains to be seen. One possibility is to introduce the requirejs style configuration data to map the path to the actual path. Currently, it is illegal to use the module identifier of bare path in browsers.

Interoperability with CJS module

  • You can import CJS modules, but they are always only exported by default – that ismodule.exportsThe value. Having the CJS module support named exports is already in progress, but it may take a while. If you can help, you can do it.
import fs1 from 'fs';
console.log(Object.keys(fs1).length); // 86

import * as fs2 from 'fs';
console.log(Object.keys(fs2)); // ['default']
  • You cannot use require() in an ES module. The main reasons are:

    • Path resolution is slightly different: ESM does not supportNODE_PATHandrequire.extensions。 Moreover, its identifier is always a URL, which can cause some subtle differences.
    • Es modules are always loaded asynchronously, which ensures maximum compatibility with the web. This loading style does not allow the CJS module to be loaded synchronously with a mix of require().
    • Disable synchronous module loading can also reserve a back path for top level await to import es module (a function currently under consideration).

3. Es module on earlier versions of node.js

If you want to use the ES module on node.js before 8.5.0, see John David Dalton’s @ STD / ESM.

Tip: if you do not enable any additional features that can be unlocked, you will be 100% compatible with the native es module in node.js

FAQ

When can I use the ES module without command line options?

The current plan is to use es module by default in node.js 10 LTS.

Further reading

For more information about node.js and ES module in browser:

  • “Making transpiled ES modules more spec-compliant” [using ES modules natively vs. transpiling them via Babel]
  • “Module specifiers: what’s new with ES modules?” [Why .mjs? How are module specifiers resolved? Etc.]
  • “Modules” [in-depth chapter on ES modules in “Exploring ES6”]

Upcoming ECMAScript proposal:

  • Blog: “es proposal:”import() – dynamically importing ES modules”
  • Proposal: “import.meta