「这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战」
url-loader 和 file-loader 的工作方式是相似的,但是可以将较小的文件,转成 base64 的 URI(即以 base64 的方式编码图片文件,这样到时候就不需要单独下载它了)。
base64的URI的好处:我们现在打包出来的是一些静态资源,现在包括
bundle.js、图片1、图片2,其实后面我们还会把项目目录下的index.html文件也进行打包。那么到时候我们就会在服务器中部署这些打包后的静态资源,然后浏览器就可以从服务器中请求这些静态资源了,而请求的过程是这样的:首先把index.html文件请求下来,然后解析该文件,里面通常会有<script>,一般会指向某个js文件,比如我们这里指向bundle.js,那么浏览器就会发送第二个网络请求,把bundle.js下载下来,然后对它进行解析,执行里面的脚本。而如果bundle.js中又通过比如background-image: url('...')或者<img>元素的src来加载图片1和图片2,那么浏览器也会发送对应的网络请求,向服务器请求这两张图片资源。因此,上面这个过程中,浏览器一共向静态服务器发送了4次网络请求(分别是对index.html、bundle.js、图片1、图片2的请求)。但是,对于较小的图片,特别是在开发中,图片是很多的,如果我们还是通过发送一个个的网络请求去获取这些小的图片,那就会对服务器造成很大压力,因为每个服务器在同一时间能够应对的并发的请求数是有限的。比如说一个客户端为了获取
50张小图片就向服务器发送了50次的请求,那必然会非常消耗性能。所以我们通常会对小图片做些优化,优化方案通常是以下3种:
- 使用雪碧图(精灵图):将所有小图片放到一张图片中,到时只需要请求这一张图片,之后通过
background-position显示这张图片中对应的小图片;- 使用字体图标:通过下载字体文件,使用里面的
class来显示对应的字体图片(图标),显示的是矢量图;- 将小图片进行
base64编码,编码成base64的URI,到时候会嵌入进对应的文件中(比如bundle.js文件或者css文件中),然后跟随着这个文件一起被下载下来,到时候浏览器可以直接解析这个base64 的 URI,然后对应的图片就能显示出来了。这就意味着,某张图片就不需要再单独发送一次请求了。
但是,前面我们使用的 file-loader 不管图片是大是小,都会对图片进行单独的打包。如果你想把大的图片进行单独的打包,而小的图片进行 base64 编码后再打包,这时,我们就可以使用 url-loader 了。我们先来安装它:
npm install url-loader -D
然后修改 webpack 的配置文件:
...
module.exports = {
...
module: {
rules: [
...
{
test: /\.(jpe?g|png|gif|svg)$/,
use: {
loader: 'url-loader', // 将之前的 file-loader 换成了 url-loader
options: {
name: 'img/[name]_[hash:6].[ext]'
}
}
}
]
}
}
由于 url-loader 的用法和 file-loader 是一样的,所以我们只需要把原先对应的规则对象使用的 file-loader 修改为 url-loader 即可。然后我们先删除项目中的 ./build 文件夹,再来打包看下效果:
你会发现,现在打包后的输出文件夹下只有 bundle.js 文件了,img 文件夹都没有生成,这是为什么呢?如果你打开这个 bundle.js,你会发现相较于之前的内容,里面多出了一大堆乱七八糟的东西,这些东西其实就是图片在经过 base64 编码后生成的内容。也就是说现在 url-loader 对我们的两张图片都进行了 base64 的编码,然后到时候会跟随着 bundle.js 一起下载下来。我们也可以从浏览器中看到 base64 编码后的内容:
url-loader 默认情况下会对所有图片都进行 base64 编码,但一般情况下,只有小的图片我们才会对其进行 base64 编码,大的图片不需要做 base64 编码,因为如果对大的图片也进行 base64 编码,会导致 bundle.js 过大,那么到时候下载 bundle.js 文件时就需要花费更多时间,那就意味着 bundle.js 中的一些脚本可能要过一段时间之后才会执行到,那么用户可能要等待一段时间后才能看到这些脚本执行后的对应效果,有可能会出现一段时间的页面白屏现象。
那么,如果我们想只对大小在 100kb 以内(不包括 100kb)的图片进行 base64 编码,就可以这样来配置:
...
module.exports = {
...
module: {
rules: [
...
{
test: /\.(jpe?g|png|gif|svg)$/,
use: {
loader: 'url-loader', // 将之前的 file-loader 换成了 url-loader
options: {
name: 'img/[name]_[hash:6].[ext]',
limit: 100 * 1024 // 小于 100kb 的图片进行 base64 编码,大于等于 100kb 的图片则进行单独的打包
}
}
}
]
}
}
我们在 options 中添加了对 limit 的设置,limit 对应一个数值,单位是 byte,因此,100kb 就可以写成 100 * 1024。修改完配置后,我们先删除项目中的 ./build 文件夹,再来打包看下效果:
可以看到,这次只有大于 100kb 的这张图片被单独打包了,而另一张小于 100kb 的图片则已经做了 base64 编码并被放进了 bundle.js 中。而且页面也依然可以正常显示:
以上,就是关于 url-loader 的使用过程。