【问题标题】:Why is Javascript module with ".js" file extension not found on import unless file extension is .mjs despite package "type" being "module"?为什么在导入时找不到具有“.js”文件扩展名的 Javascript 模块,除非文件扩展名是 .mjs,尽管包“类型”是“模块”?
【发布时间】:2021-06-05 16:53:23
【问题描述】:

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

来自Node.js v16.3.0 documentation - Determining module system(强调我的)

确定模块系统

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

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

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

现在考虑以下最小可重现示例,说明 .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.js 更改为foo.mjs,然后
  2. 更新index.js 中的import 以反映foo.mjs => import foo from './foo.mjs';

然后程序执行没有错误。

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

环境:

$ node -v
v16.3.0

【问题讨论】:

  • 在 ESM 中,file extension is mandatory。使用import foo from './foo.js'
  • 谢谢@ASDFGerte,正如你指出的那样,我也在另一个答案中发现了这个事实:stackoverflow.com/a/63460038/2291928。是的,.js 文件扩展名是强制性的。我误解了 ES Modules 和 CommonJS 之间的这种区别。谢谢!

标签: javascript node.js


【解决方案1】:

正如@ASDFGerte in their comment所指出的,在this answer to "Omit the file extension, ES6 module NodeJS"中也有充分的解释:

在 ES 模块中,file extension is mandatory,因此您不能像在 CommonJS 中那样省略 .js 文件扩展名。

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

index.js

import foo from './foo.js';

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

【讨论】:

    猜你喜欢
    • 2020-08-30
    • 1970-01-01
    • 2022-07-02
    • 1970-01-01
    • 2023-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多