Node.Js Plans to Support Import/Export Es6 (Ecmascript 2015) Modules

Node.js plans to support import/export ES6 (ECMAScript 2015) modules

Node.js 13.2.0 & Above

Node.js 13.2.0 now supports ES Modules without a flag . However, the implementation is still marked as experimental so use in production with caution.

To enable ECMAScript module (ESM) support in 13.2.0, add the following to your package.json:

{
"type": "module"
}

All .js, .mjs (or files without an extension) will be treated as ESM.

There are a number of different options other than entire package.json opt-in, all of which are detailed in the documentation for 13.2.0.

Node.js 13.1.0 & Below

Those still using older versions of Node may want to try the [esm][3] module loader, which is a production-ready implementation of the ES Modules Specificaiton for Node.js:

node -r esm main.js

Detailed Updates...

23 April 2019

A PR recently landed to change the way ECMAScript modules are detected:
https://github.com/nodejs/node/pull/26745

It's still behind the --experimental-modules flag, but there are major changes in the way modules can be loaded:

  • package.type which can be either module or commonjs
    • type: "commonjs":
      • .js is parsed as CommonJS
      • the default for an entry point without an extension is CommonJS
    • type: "module":
      • .js is parsed as an ECMAScript module
      • does not support loading JSON or a native module by default
      • the default for an entry point without an extension is ECMAScript module
  • --type=[mode] to let you set the type on entry point. Will override package.type for entry point.
  • A new file extension .cjs.
    • this is specifically to support importing CommonJS in the module mode.
    • this is only in the ECMAScript module loader, the CommonJS loader remains untouched, but the extension will work in the old loader if you use the full file path.
  • --es-module-specifier-resolution=[type]
    • options are explicit (default) and node
    • by default our loader will not allow for optional extensions in the import, the path for a module must include the extension if there is one
    • by default our loader will not allow for importing directories that have an index file
    • developers can use --es-module-specifier-resolution=node to enable the CommonJS specifier resolution algorithm
    • This is not a “feature”, but rather an implementation for experimentation. It is expected to change before the flag is removed
  • --experimental-json-loader
    • the only way to import JSON when "type": "module"
    • when enable all import 'thing.json' will go through the experimental loader independent of mode
    • based on whatwg/html#4315
  • You can use package.main to set an entry point for a module
    • the file extensions used in main will be resolved based on the type of the module

17 January 2019

Node.js 11.6.0 still lists ES Modules as experimental, behind a flag.

13 September 2017

Node.js 8.5.0 has been released with support for mjs files behind a flag:

node --experimental-modules index.mjs

The plan for this is to remove the flag for the v10.0 LTS release.

--Outdated Information. Kept here for historical purposes--

8 September 2017

The Node.js master branch has been updated with initial support for ESM modules:
https://github.com/nodejs/node/commit/c8a389e19f172edbada83f59944cad7cc802d9d5

This should be available in the latest nightly (this can be installed via nvm to run alongside your existing install):
https://nodejs.org/download/nightly/

And enabled behind the --experimental-modules flag:

package.json

{
"name": "testing-mjs",
"version": "1.0.0",
"description": "",
"main": "index.mjs" <-- Set this to be an mjs file
}

Then run:

node --experimental-modules .

February 2017:

An Update on ES6 Modules in Node.js

The Node.js guys have decided that the least bad solution is to use the .mjs file extension. The takeaway from this is:

In other words, given two files foo.js and bar.mjs , using import * from 'foo' will treat foo.js as CommonJS while import * from 'bar'
will treat bar.mjs as an ES6 Module

And as for timelines...

At the current point in time, there are still a number of
specification and implementation issues that need to happen on the ES6
and Virtual Machine side of things before Node.js can even begin
working up a supportable implementation of ES6 modules. Work is in
progress but it is going to take some time — We’re currently looking
at around a year at least.

October 2016:

One of the developers on Node.js recently attended a TC-39 meeting and wrote up a superb article on the blockers to implementing for Node.js:

Node.js, TC-39, and Modules

The basic take-away from that is:

  • ECMAScript modules are statically analyzed, and CommonJS are evaluated
  • CommonJS modules allow for monkey-patching exports, and ECMAScript modules currently do not
  • It's difficult to detect what is an ECMAScript module and what is CommonJS without some form of user input, but they are trying.
  • *.mjs seems the most likely solution, unless they can accurately detect an ECMAScript module without user-input

-- Original Answer --

This has been a hot potato for quite some time. The bottom line is that yes, Node.js will eventually support the ES2015 syntax for importing/exporting modules - most likely when the specification for loading modules is finalized and agreed upon.

Here is a good overview of what's holding Node.js up. Essentially, they need to make sure that the new specification works for Node.js which is primarily conditional, synchronous loading and also HTML which is primarily asynchronous.

Nobody knows for sure right now, but I imagine Node.js will support import/export for static loading, in addition to the new System.import for dynamic loading - while still keeping require for legacy code.

Here's a few proposals on how Node might achieve this:

  • In defense of .js
  • .mjs modules

Unable to import module in nodejs using ES6 Modules

i went through the documentation of Node and found out that when we are using ES6 to import modules then we need to define our file with extension ".mjs" instead of just ".js" and while importing the function i also mentioned the extension like this -
import { connectMongoDB } from "./config/db.mjs"; and it worked fine

Node.js export behaves differently from ES6 modules

The behavior here, which you can see in ES6 modules:

console.log(foo);  // undefined
init();
console.log(foo); // 42

should feel pretty odd in comparison to how JS normally works - foo appears to be a local identifier, but if it happens to be an import from another module, if the other module's export changes, the foo binding wherever it's imported will change as well.

Without using ES6 modules, there is no (reasonable) way to replicate that sort of behavior using a single identifier.

You can use ES6 modules in Node if you want, though. Use the original code with the ES6 module syntax, and then run:

node --experimental-modules index.mjs

Build systems like Webpack can also transpile code written in ES6 modules into vanilla JS, though such transpiled code ends up turning the imports into a namespace object. Eg, this:

import { foo, init } from "./foo";

init();
console.log(foo); // 42

will turn into something like

const fooNamespace = __webpack_require__("./foo.js");
fooNamespace.init();
console.log(fooNamespace.foo);

It's just like if you had a reference to an object which, when a function inside it is called, mutates the object. You could implement this if you wanted.

const obj = {
foo: undefined,
init() { obj.foo = 42 }
};
module.exports = obj;

Although one can use ES6 modules to make imported identifiers seemingly reassign themselves on their own, keep in mind that, since such code is potentially confusing, some prefer to avoid such patterns entirely.

Is there any performance difference in ES modules vs Common JS modules in NodeJS servers?

An import statement can reference an ES module or a CommonJS module. import statements are permitted only in ES modules, but dynamic import() expressions are supported in CommonJS for loading ES modules.

When importing CommonJS modules, the module.exports object is provided as the default export. Named exports may be available, provided by static analysis as a convenience for better ecosystem compatibility.

The major difference in commonjs and ES module is of synchronous and asynchronous nature>>
-commonjs modules are synchronous, this is'nt an issue in case of small module execution but in case of large modules it can be delay to process. while,
-loading and parsing of ES modules is asynchronous, this is the difference where may be the performance gets vary..



Related Topics



Leave a reply



Submit