Translator: huangxiaolu

The original link

Starting with version 8.5.0, Node.js supports native ES modules with a command-line option. Bradley Farias is responsible for this new feature.

This article will explain the details.

Demo

The demo version library structure is as follows:

esm-demo/
    lib.mjs
    main.mjs
Copy the code

Lib. MJS:

export function add(x, y) {
    return x + y;
}
Copy the code

The main MJS:

import {add} from './lib.mjs';

console.log('Result: '+add(2, 3));
Copy the code

Run the demo:

$ node --experimental-modules main.mjs
Result: 5
Copy the code

Matters needing attention

ES module:

  • Dynamic import of modules is not supported. But the dynamic import() operator is already under development and should be available soon.

  • There are no meta variables, such as __dirname and __filename. However, Domenic Denicola’s “import.meta” could provide similar functionality for ES modules. It might look like this:

    console.log(import.meta.url);
    Copy the code
  • All module specifiers are now urls (a new feature in Node.js) :

    • Peer files — relative paths with file extensions: ‘.. /util/tools.mjs’

    • Library — Bare path with no file extension: ‘lodash’

    • It remains to be seen how browsers will be able to use NPM installed libraries (without Bundler). One possibility is to introduce RequireJs-style configuration data that maps the bare path to the actual path. Currently, you cannot use a bare path as a module specifier in the browser.

Interoperability with CJS modules:

  • You can import CJS modules, but they always have a default value of export, which is module.exports. Making CJS modules support named exports (for example, via pragma at the beginning of files) is already on the agenda, but it may take a while. If you can help, get started.

    import fs1 from 'fs';
    console.log(Object.keys(fs1).length); // 86
    
    import * as fs2 from 'fs';
    console.log(Object.keys(fs2)); // ['default']
    Copy the code
  • You cannot use require() in ES modules. The main reasons are:

    • Path resolution works slightly differently: ESM does not support NODE_PATH and require.extensions. Also, the fact that the ESM’s specifier is always a URL leads to some subtle differences.

    • The ES module is always loaded asynchronously, which ensures maximum compatibility with the Web. This loading method does not mix with loading CJS modules synchronously through require().

    • Disabling synchronous module loading also makes it possible to implement top-level await in ES modules (which is one of the features currently under consideration).

ES module on older versions of Node.js

To use the ES module on versions of Node.js prior to 8.5.0, see John-David Dalton’s @std/ ESM.

Tip: It is fully compatible with node.js native ES modules if you don’t lock in additional new features.

FAQ

When can the ES module be enabled without command line options?

The current plan is to support the ES module by default in Node.js 10 LTS.

Further reading

More information about Node.js and the ES module in browsers:

  • “Make translated ES modules more spec compliant” [using standard ES modules vs. translated modules via Babel]

  • “Module specifier: What’s new in the ES module?” Why.mjs? How to parse the module specifier? Etc.

  • “Modules” [An in-depth look at the ES modules in “Exploring ES6”]

Upcoming ECMAScript proposals:

  • Blog post: “ES Proposal: Import () — Dynamic Import of ES modules”

  • Proposal: the “import. Meta”