This blog post describes how module specifiers (the path-like IDs of modules) change with ECMAScript modules (ESM). There are a few subtle differences, compared to the familiar CommonJS module (CJS) style.
1. Why a new filename extension for ES modules?
Node.js will support ES modules via the new filename extension .mjs (also known jokingly as “Michael Jackson Script”). Many web developers would have preferred to stick with .js. Let me make the case why .mjs is the better approach.
The core thing to keep in mind is: In order to distinguish between CommonJS modules and ES modules, you need some kind of metadata. Browsers face a similar problem, having to distinguish between scripts and modules. They attach the metadata via the attribute module in <script> elements.
3. How do module specifiers change with ESM?
The key change with ES modules is:
All ES module specifiers must be valid URLs
In particular, if the filename of a module has an extension then its specifier must have one, too. That is exactly like non-module <script> elements work today.
The following import statements all have legal module specifiers:
import * as foo from 'http://example.com/lib/foo.mjs'; import * as foo from '/lib/foo.mjs'; import * as foo from './foo.mjs'; import * as foo from '../foo.mjs';
For compatibility with CommonJS and in preparation for future features, relative paths that don’t start with ./ or ../ are not allowed:
// Not allowed: import * as foo from 'foo.mjs'; import * as foo from 'lib/foo.mjs';