这是我参与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
就可以了。