Node无法找到没有.js扩展名的模块。

38

我有一个文件test.js,里面含有以下代码:

import {blabla} from "./bla";

async function dataGenerator() {
..........
}

(async() => {
  console.log('1')
  await dataGenerator()
  console.log('2')
})()

当我尝试使用终端运行node test.js时,它返回错误:

注意:忽略导入结构。这只是针对问题的虚构内容。在我的文件中,导入是自动完成的。

Cannot find module 'D:\bla' imported from D:\test.js

我已将以下行添加到package.json文件中:"type": "module"。没有这行代码将返回:

Cannot use import statement outside a module

我正在使用node v14。如何在不为所有导入的文件添加".js"的情况下运行test.js。由于存在函数嵌套,因此将.js扩展名添加到每个导入的文件中很复杂。是否有任何npm可用于运行它?


路径正确吗?我的意思是,你写了"../",但是你的test.js已经在根目录中了。 - binaryRat
@binaryRat 是的可以。就像我在问题中所说的那样:注意:忽略导入结构。这只是为了提出问题而虚构的。在我的文件中,导入是自动的。 - icsul
使用实验标志运行节点的问题在于未来节点版本中缺乏未来支持。请参见此节点开发人员的警告。您可能的另一种方法是为编译测试代码使用单独的tsconfig文件。因此,对于库代码,您可以使用module:“ES6”(或ESwhatever),而对于测试代码,您可以使用module:“CommonJS”。顺便说一下 - 使用tsconfig extends功能,您可以继承并修改所需的设置。我现在尝试它。 - Craig Hicks
好的 - 我在上一条评论中提出的建议失败了。这里有一个清晰的解释。Common JS 调用 ESM 是不可行的。尽管如此,关于 Node.js 对实验性功能缺乏未来支持的部分仍然是正确的。我认为这意味着如果你的项目是一个库,输出 CommonJS 和 ESM 都是一个好策略 - 让每个人都满意。但是不想两次运行 TS 类型检查器 - 这需要时间成本。想法 - 输出 TS ESM(目标 ES*),然后使用 rollup 创建 ESM 和 CJS 版本。 - Craig Hicks
你的测试代码可以保持CJS不变,这样你就可以导入rollup CJS输出。或者使用ESM测试代码导入rollup ESM输出——虽然这可能会带来一些麻烦和未来的不确定性。只使用ESM测试代码的问题在于将来可能会发现新版Node不再支持它。 - Craig Hicks
1个回答

41

在使用ES模块的import时,Node.js默认不会尝试猜测文件扩展名。这与使用require的CommonJS模块不同。

ES模块加载器文档中,您可以了解到如何在磁盘上查找文件。

'自定义ESM指示符解析算法'标题中写道:

可以使用--experimental-specifier-resolution=[mode]标志来自定义扩展名解析算法。默认模式是explicit,需要向加载器提供模块的完整路径。要启用自动扩展名解析并从包含索引文件的目录导入,请使用node模式。


6
ESM模块系统是由ECMA的语言管理者,特别是TC-39组开发的。CommonJS模块系统(首先出现)是在Mozilla开发的。如果您更喜欢它的行为,可以自由使用CommonJS - 它没有被弃用。然而,ESM模块可以更轻松地在浏览器或Node替代品(例如Deno)之间共享。 - RickN

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接