这是我参与8月更文挑战的第28天,活动详情查看:8月更文挑战
前面三篇文章讲了 webpack 加载处理其它资源,主要讲了如何加载图片资源,有两种 loader 可以选择。一个是 file-loader,另一个是 url-loader,相较于 file-loader,url-loader 有一个 limit 可以设置,然后根据当前文件的大小,决定是否进行 base64 的编码。如果进行 base64 的编码,那么编码成 base64 的字符后就会直接和页面一起请求下来;否则就还是使用 file-loader 将图片打包成图片文件,到时候每个图片文件分别进行单独的 http 请求。
但是,file-loader 和 url-loader 是在 webpack 5 之前处理其它资源经常采用的方式,而从 webpack 5 开始,我们其实可以采用另外一种方式来处理其它资源了。
在进入正文之前,我们一个问题做下说明:
- 前面执行
npm run build进行打包的时候,每次重新打包前我们都要手动把上一次打包的build文件夹删除掉,有没有办法让它在打包的时候先自动删除呢?- 有,我们后面就会讲到;
前期准备:
- 将
03_webpack处理其它资源目录重命名为03_webpack处理其它资源1,并删除里面的node_modules和build文件夹,; - 在
01_learn_webpack目录下拷贝一份03_webpack处理其它资源1,并重命名为04_webpack处理其它资源2; - 打开
VS Code的终端,切换目录到04_webpack处理其它资源2下,运行npm install安装当前项目所需依赖;
1 Asset Modules type 的介绍
- 我们当前使用的
webpack版本是webpack 5:- 在
webpack 5之前,我们常用raw-loader(可以以字符串形式导入文件)、url-loader、file-loader这些loader加载资源; - 在
webpack 5之后,我们可以直接使用**资源模块类型(Asset Modules type)**来替代上面的这些loader;
- 在
- 资源模块类型(
Asset Modules type)通过添加4中新的模块类型替换了所有这些loader:asset/resource发出一个单独的文件并导出URL。之前通过使用file-loader实现;asset/inline导出一个资源的data URI。之前通过使用url-loader实现;asset/source导出资源的源代码。之前通过使用raw-loader实现;asset在导出一个data URI和发出一个单独的文件之间自动选择。之前通过使用url-loader,并配置资源大小限制实现。
2 Asset Modules type 的使用
既然在 webpack 5 中可以用资源模块类型替代 file-loader 和 url-loader 了,那我们以后就可以不用这两个 loader 了,所以我们可以在项目中将它们卸载了:
npm uninstall file-loader url-loader
然后,来到 wk.config.js 文件中,找到之前匹配图片文件的规则:
{
test: /\.(png|jpe?g|gif|svg)$/,
use: [
{
// loader: 'file-loader',
loader: 'url-loader',
options: {
name: 'img/[name].[hash:6].[ext]',
limit: 100 * 1024
}
}
]
}
先简单修改如下:
{
test: /\.(png|jpe?g|gif|svg)$/,
type: 'asset/resource' // 相当于 file-loader 的效果
}
再来运行 npm run build 命令,就可以成功打包了。并且,此时图片默认打包到输出目录的根目录下:
那如何可以自定义文件的输出路径和文件名呢(像前面使用 file-loader 时那样指定文件的存放位置,把所有图片放到一个文件夹里)?有两种方式:
-
针对所有的资源模块进行设置。在顶级的
output中配置assetModuleFilename,比如如果想要把所有资源模块都放到img目录下:module.exports = { // ... output: { // ... assetModuleFilename: 'img/[name].[hash:6][ext]' } // ... }这里同样可以使用
placeholders,但与file-loader的placeholders中的[ext]不同,这里的[ext]生成的扩展名中本身就会带有.,所以[ext]前不需要再加.。配置完后先删除项目目录下的
build目录,再来运行npm run build,结果如下: -
针对模块的某一规则单独进行设置。配置
Rule.generator.filename:{ test: /\.(png|jpe?g|gif|svg)$/, type: 'asset/resource', // 相当于 file-loader 的效果 generator: { filename: 'img/[name].[hash:6][ext]' } }配置完后先删除项目目录下的
build目录,再来运行npm run build,结果和上面配置output.assetModuleFilename后的结果是一样的。
如果想要实现使用了 url-loader 的效果,可以这样设置规则:
{
test: /\.(png|jpe?g|gif|svg)$/,
type: 'asset/inline' // 相当于 url-loader 的效果
}
注意:因为是 asset/inline,导出的是资源的 data URI,而不再会导出单独的文件,所以不需要再配置 Rule.generator.filename 了。
配置完后先删除项目目录下的 build 目录,再来运行 npm run build,结果如下:
对于 asset/source,可以用来导出 txt 文件、json 文件,但一般用的较少,这里就不做演练了。最后再来说下 asset,前面我们在讲 url-loader 时说过,如果有的资源比较大,可以把它打包成对应的单独的文件,而如果有的资源比较小,再打包成单独的文件做单独的请求可能有点浪费资源,这时就可以转换成 base64 的编码。那么对于资源模块类型,想要实现这个需求(url-loader 的 limit 效果),就可以将资源模块类型设置为 asset 类型:
{
test: /\.(png|jpe?g|gif|svg)$/,
// type: 'asset/resource', // 相当于 file-loader 的效果
// type: 'asset/inline', // 相当于 url-loader 的效果
type: 'asset',
generator: {
filename: 'img/[name].[hash:6][ext]'
},
parser: {
dataUrlCondition: {
maxSize: 100 * 1024 // 100kb
}
}
}
即如果资源的大小小于 100kb,就将其当做 asset/inline 类型处理(导出资源的 data URI),否则当做 asset/resource 类型处理(打包成单独的文件并导出 URL)。
配置完后先删除项目目录下的 build 目录,再来运行 npm run build,结果如下:
可以看到,大小大于 100kb 的那张图片被单独打包了,而大小小于 100kb 的那张图片已经被打包成了 base64 编码放进了 bundle.js 文件中。
总结:在
webpack 5中,关于加载资源文件,我们不再需要单独去安装file-loader和url-loader了,我们直接去使用webpack 5提供的Asset Modules type就可以了。