在前端开发中,我们经常需要导入其他模块来完成我们的任务。然而,在导入模块时,如果没有添加后缀名,就会出现各种问题。为了避免这种问题的出现,ES11 引入了一种新的语法,可以让我们在导入模块时自动添加后缀名。
为什么要自动添加后缀名
在讲解自动添加后缀名之前,我们先来了解一下没有后缀名会带来什么问题。
对于导入模块,我们常常使用 import 语句,比如:
import foo from './foo';
这个语句会导入 ./foo 文件中默认导出的内容。但是如果我们在导入时没有添加后缀名,就可能会出现找不到模块的情况。
举个例子,假如我们有两个文件:foo.js 和 foo.ts。如果我们在同一个文件夹中创建一个叫做 index.js 的文件,并在该文件中导入 foo:
import foo from './foo';
这个语句应该会导入 foo.js 文件中默认导出的内容。但是如果我们忘了给 foo.js 添加后缀名,那它将会按照以下方式去寻找:
- 查找 ./foo 目录
- 在 ./foo 目录下查找 package.json 文件
- 在 package.json 文件中查找 "main" 字段指定的文件
- 如果 package.json 中没有指定 "main" 字段,则尝试查找 index.js、index.json 和 index.node 文件
如果以上步骤都找不到文件,则会抛出导入错误,从而导致我们的应用程序无法工作。
因此,在导入模块时,我们应该始终加上后缀名。但由于有时候我们会犯糊涂,因此我们需要一种可以自动添加后缀名的语法。
使用 import() 函数
ES11 中的 import() 函数可以在导入时自动为模块添加后缀名。这个函数的语法如下:
import(moduleSpecifier)
其中,moduleSpecifier 是一个字符串,表示要导入的模块的路径。这个路径应该是相对于当前模块的路径。
例如,如果要导入 ./foo.js 文件中默认导出的内容,可以这样写:
import('./foo.js').then(foo => { console.log(foo.default); });
这样,无论我们是否在导入语句中添加后缀名,都可以正确地导入模块并使用其默认导出内容。
使用 import.meta.url
除了 import() 函数之外,ES11 还引入了一个新的全局对象:import.meta。这个对象内部包含了当前模块的相关信息,其中,.url 字段可以返回当前模块的 URL。
我们可以使用 .url 字段来获取当前模块的路径,并在导入其他模块时添加后缀名。例如,我们可以这样写:
import(`${import.meta.url.split('/').slice(0, -1).join('/')}/foo.js`) .then(foo => { console.log(foo.default); });
这样,我们就可以在导入模块时自动添加后缀名了。
后缀名的选择
在使用自动添加后缀名的语法时,我们可能会想知道该使用哪个后缀名。由于不同的文件类型有不同的后缀名,因此我们需要在导入时根据模块的类型添加不同的后缀名。
例如,对于 JavaScript 模块,我们应该添加 .js 后缀名;对于 TypeScript 模块,我们应该添加 .ts 或 .tsx 后缀名;对于 CSS 模块,我们应该添加 .css 后缀名。
但是,由于现在流行的模块打包工具(如 Webpack 和 Rollup)都已经支持在导入时自动解析文件类型,因此我们其实不需要手动添加后缀名。我们可以直接导入模块,并让打包工具自动解析类型。
例如,我们可以这样导入一个 TypeScript 模块:
import foo from './foo.ts';
由于现在大多数打包工具都可以自动解析 .ts 后缀名,因此我们不需要手动添加后缀名。
总结
ES11 中的 import() 函数和 import.meta.url 可以帮助我们在导入模块时自动添加后缀名。这个语法可以避免由于忘记添加后缀名而导致的问题,使我们的代码更加健壮。但是,在大多数情况下,我们不需要手动添加后缀名,因为现代的打包工具已经支持自动解析文件类型。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/659fb3ffadd4f0e0ff83a060