为什么在导入时找不到带有“.js”文件扩展名的 Javascript 模块,除非文件扩展名是 .mjs,尽管包“类型”是“模块”?

2023-12-19

鉴于 ECMAScript 文档中的以下引用和最小的可重现代码示例, 为什么使用.jsJavascript ES 模块导入的文件扩展名会导致ERR_MDOULE_NOT_FOUND错误时package.json has "type": "module"?

From Node.js v16.3.0 文档 - 确定模块系统 https://nodejs.org/api/packages.html#packages_determining_module_system(强调我的)

确定模块系统

当作为初始输入传递给 Node 时,或者当 ES 模块代码中的 import 语句引用时,Node.js 会将以下内容视为 ES 模块:

  • 以 .mjs 结尾的文件。
  • 当最近的父 package.json 文件包含值为“module”的顶级“type”字段时,以 .js 结尾的文件。

该文档说.js只要我们将包的类型声明为,文件扩展名就会被视为 ES 模块module.

现在考虑以下最小的可重复示例.js文件不会被视为 ES 模块,除非重命名为.mjs.


package.json

{
    "type": "module"
}

foo.js

export default 'foo module';

index.js

import foo from './foo';

console.log("Hello", foo);

使用上述文件名和代码,会出现以下错误。

$ 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'
}

但是,如果我改变以下内容

  1. change foo.js to foo.mjs, and
  2. 更新import in index.js反射foo.mjs => import foo from './foo.mjs';

然后程序就可以正常执行了。

为什么是.mjs当文档明确指出设置时,在这种情况下需要文件结尾"type": "module" in package.json应该意味着节点对待常规.js像 ES 模块这样的文件?

环境:

$ node -v
v16.3.0

正如所指出的@ASDFGerte 在他们的评论中 https://stackoverflow.com/questions/67851875/why-is-javascript-module-with-js-file-extension-not-found-on-import-unless-fi/67852006#comment119930181_67851875,并在中也有充分解释这是“省略文件扩展名,ES6 模块 NodeJS”的答案 https://stackoverflow.com/questions/63459159/omit-the-file-extension-es6-module-nodejs/63460038#63460038:

在 ES 模块中,文件扩展名是强制性的 https://nodejs.org/api/esm.html#esm_mandatory_file_extensions,所以你不能省略.js像 CommonJS 中一样的文件扩展名。

这就是我困惑的根源。一旦我包含了文件扩展名,ES 模块就可以工作了。例如,这有效。

index.js

import foo from './foo.js';

该解决方案感觉非常明显,但在不知道确切原因的情况下,CommonJS 约定和 ES 模块之间的这种差异无论如何都会感觉像是一个错误,所以我很高兴了解每个模块系统如何处理其文件扩展名。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么在导入时找不到带有“.js”文件扩展名的 Javascript 模块,除非文件扩展名是 .mjs,尽管包“类型”是“模块”? 的相关文章

随机推荐