- The solution must be 100% backward-compatible.
- In the far future, developers should be able to write Node programs and libraries without knowledge of the CommonJS module system.
- Module resolution rules should be reasonably compatible with the module resolution rules used by browsers.
- The ability to import a legacy package is important for adoption.
There is no change to the behavior of require
. It cannot be used to import ES6 modules.
Motivation: This ensures 100% backward-compatibility, while still allowing some freedom of design.
The only folder entry point for ES6 modules is "default.js". "package.json" files are not used for resolving ES6 module paths.
Motivation: A distinct entry point file name ("default.js") allows us to detect when a user is attempting to import from a legacy package or a folder containing legacy modules.
When import
ing a file path, file extensions are not automatically appended.
Motivation: The default resolution algorithm used by web browsers will not automatically append file extensions.
When import
ing a directory, if a "default.js" file cannot be found, the algorithm will attempt to find an entry point using legacy require
rules, by consulting "package.json" and looking for "index.*" files.
Motivation: This provides users with the ability to
import
from legacy packages.
- "default.html" is frequently used as a folder entry point for web servers.
- The word "default" has a special, and similar meaning in ES6 modules.
- Despite "default" being a common English word, "default.js" is not widely used as a file name.
In a random sampling of 25,000 NPM packages (10% of the total number of packages), "default.js" was only found one time in a package root. This particular "default.js" file was already an ES6 module. As a filename, "default.js" was found only 174 times. By contrast, "index.js" was found 22,607 times, and in the package root 10,282 times.
Loads X from a module at path Y. T is either "require" or "import".
- If X is a core module, then
- return the core module
- STOP
- If X begins with './' or '/' or '../'
- LOAD_AS_FILE(Y + X, T)
- LOAD_AS_DIRECTORY(Y + X, T)
- LOAD_NODE_MODULES(X, dirname(Y), T)
- THROW "not found"
- If T is "import",
- If X is a file, then
- If extname(X) is ".js", load X as ES6 module text. STOP
- If extname(X) is ".json", parse X to a JavaScript Object. STOP
- If extname(X) is ".node", load X as binary addon. STOP
- THROW "not found"
- If X is a file, then
- Else,
- Assert: T is "require"
- If X is a file, load X as CJS module text. STOP
- If X.js is a file, load X.js as CJS module text. STOP
- If X.json is a file, parse X.json to a JavaScript Object. STOP
- If X.node is a file, load X.node as binary addon. STOP
- If T is "import",
- If X/default.js is a file, load X/default.js as ES6 module text. STOP
- NOTE: If X/default.js is not a file, then fallback to legacy behavior
- If X/package.json is a file,
- Parse X/package.json, and look for "main" field.
- let M = X + (json main field)
- LOAD_AS_FILE(M, "require")
- If X/index.js is a file, load X/index.js as JavaScript text. STOP
- If X/index.json is a file, parse X/index.json to a JavaScript object. STOP
- If X/index.node is a file, load X/index.node as binary addon. STOP
- let DIRS=NODE_MODULES_PATHS(START)
- for each DIR in DIRS:
- LOAD_AS_FILE(DIR/X, T)
- LOAD_AS_DIRECTORY(DIR/X, T)
When a user executes
$ node my-module.js
from the command line, there is absolutely no way for Node to tell whether "my-module.js" is a legacy CJS module or an ES6 module. In the interest of backward compatibility, Node should probably attempt to load the file as a CJS module, and fallback to ES6 if there is a syntax error indicating the presence of import
declarations. As people move away from CJS modules in general, future Node versions can assume that the file is an ES6 module.
Also, would like to note that
package.json
main
is optional: see https://registry.npmjs.com/npm-index-test/1.0.0 & https://registry.npmjs.com/npm-index-test/2.0.0 . In light of this, and the overwhelming number of existingindex.js
and heavily usedindex.html
in web servers I don't think we need to change fromindex
todefault