摘要:在开发的时候有时候会遇到单文件大量引入文件的场景,如router.config中,需要引入的文件较多,并不是很友好,通过webpack的 APIrequire.context() 可以实现自动化导入模块,进而简化这一操作。
案例:如下的文件中引入大量图片(当然这不是个好的案例,此处先不考虑这些)
优化之后的效果:
1. 带表达式的 require 语句
注意:这里的require并非CommonJS中的require,而是 webpack 提供的特定的方法。区别如下:
如果 require 中含有表达式,由于编译时并不清楚
具体导入了哪个模块,因此会创建一个上下文。
🌰 举个栗子,有如下目录
assest
│
└───images
│ │ png1.svg
│ │ png1.svg
│ │
│ └───icons
│ │ icon1.svg
│ │ icon2.svg
也就是说在执行
require('./assets/images/' + name + '.svg');
的时候,webpack 会解析 require() 调用,然后提取出如下一些信息
Directory: ./assets
Regular expression: /^.*\.svg$/
1.1 上下文环境
在解析 require()的过程中,会创建一个上下文环境。它包含 对该目录下所有模块 的引用,可以使用匹配正则表达式的请求来导入这些模块。上下文模块中存在一个映射,该映射用于将请求转换为模块 ID:
{
"./png1.svg": 0,
"./png2.svg": 1,
"./icons/icon1.svg": 2
"./icons/icon2.svg": 3
}
2. require.context
require.context(directory, useSubdirectories = true, regExp = /^\.\/.*$/)函数可以实现自定义{{embed 上下文环境}}。
参数说明:
directory:要搜索的目录useSubdirectories:是否还搜索其子目录regExp:匹配文件的正则表达式
🌰 示例:
require.context('./test', false, /\.test\.js$/);
// 创建一个上下文,其中文件直接来自 test 目录,require 包含的表达式以 `.test.js` 结尾。
require.context('../', true, /\.stories\.js$/);
// 创建一个上下文,其中文件来自父文件夹及其所有子级文件夹,require 包含的表达式以 `.stories.js` 结尾。
注意: 传递给 require.context 的参数必须是字面量!
2.1 上下文模块 API
上下文模块(require.context())会返回:接收一个 request 参数的 require 函数,如下:
使用
Object.getOwnPropertyNames() 可以看到此函数有三个属性:resolve,keys 与 id:
属性值说明:
resolve 是一个函数,它返回 request 被解析后得到的模块 id。
keys 也是一个函数,它返回一个数组,该上下文环境查到的所有文件名字组成的内容:
3. 组织自动引入的内容实现工程化
这里以引入图片做为案例,路由文件类似:
- 定义工具函数
export function importAll<T>(requireContext, fileType): T {
const fileMap: Partial<T> = {};
requireContext.keys().forEach((key) => {
const regex = new RegExp(fileType, 'g');
const fileName = key.replace(/(\.)|(\/)/g, '').replace(regex, '');
fileMap[fileName] = requireContext(key);
});
return fileMap as T;
}
- 在文件目录定义导出函数
// /assets/homeIcon/index.ts
import { importAll } from '@/utils/importFile';
const context = require.context('./', false, /^.\/\w+\.png$/);
// 定义文件名类型,在别处引用时能自动给出提示
type FileNames = 'icon1' |
'icon2' |
'icon3' |
'icon4' |
'icon5';
type FileObject = {
[Prop in FileNames]: string
}
const fileMap = importAll<FileObject>(context, 'png');
export default fileMap;
- 在引入文件中使用
import homeIcon from '@/assets/homeIcon';
...
<img src={homeIcon.icon1} alt="" />
<img src={homeIcon.icon2} alt="" />
<img src={homeIcon.icon3} alt="" />