工作中遇到一个问题,由于我的页面渲染需要大量的图片,大约四五百张,我采用的方法如下
引入完这些图片简直眼花缭乱手抽筋,一整个大崩溃!!!
这时候我的po如一道救赎的光来临,给我这个小卡拉米上了一课,可以使用Webpack的require.content方法
const imgs = require.context("../../assets/QWeather-Icons-1.6.0/icons", true);
export const imgMap = imgs.keys().reduce((obj, key) => {
const name = key
.replace(/(\.\/)|(\.jpe?g)|(\.png)|(\.svg)/g, "");
obj[name] = imgs(key);
return obj;
}, {});
七行代码替代了我八百多行代码,惭愧惭愧啊
后面通过学习我了解到,require.content是Webpack提供的一个方法,用于动态引入,可以让你在编译时将一个目录中的所有模块自动导入。 如果想引入一个文件夹下面的所有文件,或者引入能匹配一个正则表达式的所有文件,这个功能就会很有帮助。官方文档:依赖管理 | webpack 中文文档
require.content语法:
包含三个参数:
- directory:要搜索的目录
- useSubdirectories:是否还搜索其子目录
- egExp:匹配文件的正则表达式
require.context(
directory,
(useSubdirectories = true),
(regExp = /^./.*$/)
);
常用正则:
`^`: 匹配字符串的开始位置
`.*`: .匹配任意字符,*匹配数量0到正无穷
`.`: 斜杠用来转义,`.`匹配.
`(jpg|gif|png|bmp)`: 匹配 jpg 或 gif 或 png 或 bmp
`$`: 匹配字符串的结束位置
`i`: 不区分大小写。
当 Webpack 编译时,require.context 会根据传入的参数在指定的目录中进行递归搜索,并返回一个函数。这个函数有三个属性:resolve、keys 和 id。
- resolve:是一个函数,用于解析模块请求,它接受一个参数,即请求的模块路径,返回这个模块对应的 id。这样可以方便地根据模块路径获取模块 id,用于在构建时动态引入模块。
- keys:也是一个函数,它返回一个数组,包含了指定目录下所有匹配的模块的相对路径。这个数组可以被遍历,用于动态加载模块。
- id:是上下文模块的模块 id。这个 id 在 Webpack 构建过程中是唯一的,可以用于标识这个上下文模块。
解析:
如果 require 中含有表达式,由于编译时并不清楚具体导入了哪个模块,因此会创建一个上下文。 例:
require('./template/' + name + '.ejs'); //在当前文件下的 template 文件下,匹配以 .ejs 为结尾的文件
webpack 解析会require()调用,提取出文件名以及文件类型,并且创建一个context module上下文模块。包含对该目录下所有模块的引用。上下文模块中存在一个映射,该映射用于将请求转换为模块 ID。
而require.context()
函数可以实现自定义上下文,我们可以通过 require.context() 函数
来创建自己的 context
。例
require.context('./main', false, /.name.js$/);
// 创建一个上下文,其中文件直接来自 main 目录,require 包含的表达式以 `.name.js` 结尾。
require.context('../', true, /.name.js$/);
// 创建一个上下文,其中文件来自父文件夹及其所有子级文件夹,require 包含的表达式以 `.name.js` 结尾。
-
在 Webpack 编译时,当遇到 require.context 声明时,Webpack 会根据传入的参数进行递归文件搜索,并生成一个模块列表。
-
然后,在运行时,当调用 require.context 返回的函数时,实际上是根据之前生成的模块列表进行动态模块引入。
require.content()的优点
- 减少冗余代: 无需手动导入每个模块,减少了重复的代码,提高了开发效率。
- 易于维护: 添加新模块时,只需将文件放入指定目录,无需修改导入代码。
- 灵活性高: 可以根据不同的正则表达式匹配不同的文件,实现灵活的模块导入策略。