Node.js 8.5.0 was released recently with a few features such as copyFile() and copyFileSync() methods on the file system module fs, a minimal implementation of console.group(), and, most importantly, the support for ES2015 modules behind the --experimental-modules flag only. But what took so long to implement such feature, especially that most of the ES2015 featured were there almost from the beginning? Well... There was a bit of a problem.

The Problem That Delayed The Implementation Of ES2015 Modules

Node.js has used CommonJS specifications to deal with importing and exporting modules. Using require(), we would be able to import a module, and exports to export a module.

// importing modules
const { myModule } = require('lib/myModule.js');

// exporting modules
exports.myModule2 = function() {
    //...
}

Now, this is quite similar, syntactically to importing and exporting modules in ES2015.

// importing modules
import { myModule } from 'lib/myModule.js'

// exporting modules
export function myModule2 () {
    //...
}

However, the semantics between CommonJS and ES2015 approach is different, which is the main reason behind this delay. While Node's require() loads the modules when requested during the code execution, ES2015 modules are parsed (without being executed). Therefore, at the runtime, the engine will look for imports, load them and run the code.

The Solution

There’s been plenty of proposals regarding this issue, and lastly the approved proposal was to use the .mjs extension for the files that contain the ES2015 modules.

This was known as the Michael Jackson Solution.

This solution is good for many reasons when compared to the other proposed approaches. The .mjs files also work in the browser, but they have to be served with the correct Media Type (text/javascript or application/javascript).

The current plan is to make ES modules available by default in Node.js 10 LTS.

References