首页 > 解决方案 > 为什么在导入时找不到具有“.js”文件扩展名的 Javascript 模块,除非文件扩展名是 .mjs,尽管包“类型”是“模块”?

问题描述

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

来自Node.js v16.3.0 文档 - 确定模块系统(强调我的)

确定模块系统

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

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

文档说,.js只要我们将包的类型声明为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. 更改foo.jsfoo.mjs, 和
  2. 更新importinindex.js以反映foo.mjs=>import foo from './foo.mjs';

然后程序执行没有错误。

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

环境:

$ node -v
v16.3.0

标签: javascriptnode.js

解决方案


正如@ASDFGerte 在他们的评论中所指出的那样,并且在“省略文件扩展名,ES6 模块 NodeJS”的答案中也得到了充分的解释:

在 ES 模块中,文件扩展名是强制的,所以你不能.js像在 CommonJS 中那样省略文件扩展名。

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

index.js

import foo from './foo.js';

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


推荐阅读