Given the following quote from the ECMAScript documentation and minimal reproducible code example,
why does using the .js
file extension for an Javascript ES module import cause an ERR_MDOULE_NOT_FOUND
error when package.json
has "type": "module"
?
From Node.js v16.3.0 documentation - Determining module system (emphasis mine)
Determining module system
Node.js will treat the following as ES modules when passed to node as the initial input, or when referenced by import statements within ES module code:
- Files ending in .mjs.
- Files ending in .js when the nearest parent package.json file contains a top-level "type" field with a value of "module".
The documentation says that a .js
file extension is treated as an ES module as long as we declare our package's type as module
.
Now consider the following minimal reproducible example of how a .js
file does not get treated as an ES Module unless renamed to .mjs
.
package.json
{
"type": "module"
}
foo.js
export default 'foo module';
index.js
import foo from './foo';
console.log("Hello", foo);
With the above file names and code, the following error occurs.
$ node index.js
node:internal/process/esm_loader:74
internalBinding('errors').triggerUncaughtException(
^
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/Users/georgep/nodemodulestest/foo' imported from /Users/georgep/nodemodulestest/index.js
Did you mean to import ../foo.js?
at new NodeError (node:internal/errors:363:5)
at finalizeResolution (node:internal/modules/esm/resolve:307:11)
at moduleResolve (node:internal/modules/esm/resolve:742:10)
at Loader.defaultResolve [as _resolve] (node:internal/modules/esm/resolve:853:11)
at Loader.resolve (node:internal/modules/esm/loader:89:40)
at Loader.getModuleJob (node:internal/modules/esm/loader:242:28)
at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:73:40)
at link (node:internal/modules/esm/module_job:72:36) {
code: 'ERR_MODULE_NOT_FOUND'
}
But, if I change the following
- change
foo.js
tofoo.mjs
, and - Update the
import
inindex.js
to reflectfoo.mjs
=>import foo from './foo.mjs';
Then the program executes without error.
Why is the .mjs
file ending necessary in this situation, when the documentation clearly states that setting "type": "module"
in package.json
should mean that node treats regular .js
files like ES modules?
Environment:
$ node -v
v16.3.0