JavaScript的import如何在没有扩展名的情况下找到模块?

29
我知道我们可以使用import {x} from "./file"导入同一目录下的file.js中的变量x。如果目录中有不同扩展名的同名文件,这种情况将如何处理呢?
例如,如果同一目录下有file.jsfile.ts文件,那么import {x} from "./file"会怎样表现呢?这是否取决于JavaScript的版本?

某些打包工具可能允许或要求使用该扩展名,请检查您的环境。您可以浏览Webpack / Rollup /其他源代码。 - Phil
2个回答

42
是否取决于JavaScript的版本?
不是,它取决于JavaScript运行时的行为,也就是执行脚本的东西。在支持ES模块的浏览器中,不会添加扩展名到你导入的URL中 - 如果你的文件例如有.js扩展名,你必须写成“import {x} from './file.js'”。浏览器无法查找服务器上哪些具有哪些扩展名的文件是可用的。在没有原生支持ESM的浏览器中,你必须将模块转译为可以在浏览器中运行的捆绑格式。在这种情况下,它取决于您选择使用的特定捆绑器的行为(见下文)。在支持ESM的Node.js版本中,运行时不会搜索扩展名,但会按名称从node_modules解析模块。例如,“import 'lodash'”可以解析为“./node_modules/lodash/index.mjs”,而无需知道“index.mjs”的扩展名。在不支持ESM的Node.js版本中,不能使用import,必须先将模块转换为CommonJS格式,最终使用require。require具有一个它将搜索文件系统的扩展名列表。例如,如果在同一目录中有file.js和file.ts文件,那么import {x} from "./file"会怎样运行取决于不同的情况。
当你转译或编译脚本时,哪些扩展名被认可取决于编译器和你提供的编译设置。例如,在webpack中,有一个预定义的支持扩展名列表 - ".wasm", ".mjs", ".js", ".json",但是您可以通过在webpack.config.js文件中使用resolve.extension设置来更改它。
如果您使用webpackts-loader插件,.ts文件扩展名也会被识别,但加载程序将尝试使.ts文件编译为.js文件,并会在捆绑时尝试使用已编译的.js文件。

如果您使用纯TypeScript编译器编译脚本,编译器将查找扩展名为'.ts'的文件进行类型检查,但在运行脚本时将生成代码以查找扩展名为'.js'的文件。此外,如果编译扩展名为'.ts'的文件,则编译器将在扩展名为'.js'的文件中编写生成的代码,并根据设置覆盖您的JavaScript文件(具体取决于输出'.js'文件的位置设置)。


HTML规范的角度来看,允许没有扩展名的模块规范符。 - Kaiido
2
从HTML规范的角度来看,没有扩展名的模块指示符是允许的。但这有点误导人:HTML规范不允许搜索扩展名。它只会找到一个被引用的资源,如果该资源本身没有扩展名。因此,在./file的情况下,它只会找到一个确切叫做./file的东西,而不是./file.mjs或其他任何东西。 - Jan Olaf Krems
2
我目前使用的纯TypeScript编译器与此处描述不符;它没有在编译后的代码中将“.js”添加到“import {x} from './file'”。看起来,如果您写入“import {x} from './file.js'”,那么它确实仍将使用“file.ts”进行编译和类型检查,并生成具有未更改文件名的js,以便它可以正常工作。 - PeterT
使用“import 'lodash'”会解析到“./node_modules/lodash/index.mjs”。如果该文件夹同时包含“index.mjs”和“index.js”,会发生什么? - Panu Logic
这取决于 lodash 的“package.json”文件中的“main”和“exports”设置,如文档中的“包入口点”部分所述。 - artem

3

@PeterT的描述对我有帮助,但我还是想多解释一下。在开发中,所有配置和打包都由webpack完成,因此我们无需进行任何这样的操作。当我们自己学习模块并希望使用基本的TypeScript编译器进行实验时,我们肯定需要像这样做。

在TypeScript文件中,导入部分需要在import段中包含.js扩展名,如下所示:

import {x} from 'X.js';//记得要包含“.js”


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