url-loader是上一节讲的 file-loader 的增强版,它支持file-loader的所有功能,另外还有一个特殊的功能。
一、url-loader的base64编码
url-loader的特殊功能是可以计算出文件的base64编码,在文件体积小于我们指定的值(单位 byte)的时候,可以返回一个base64编码的DataURL来代替访问地址。
使用base64编码的好处是可以减少一次网络请求,提升页面加载速度。
举个例子,正常img引入图片地址是
<img src="be735c18be4066a1df0e48a1173b538e.jpg">
使用base64编码后,引入图片地址是"data:image/jpg;base64,iVBORw0KGgoA…"这种格式的,这样就不用去请求存储在服务器上的图片了,而是使用图片资源的base64编码。
<img src="data:image/jpg;base64,iVBORw0KGgoA..."> <!-- 省略号...表示省略了剩下的base64编码数据 -->
在CSS中引入图片也是同样的道理。
这也是url-loader起这个名字的原因,因为它可以使用base64编码的URL来加载图片。
我们来改造一下 https://github.com/jruit/webpack-tutorial 的webpack3-4例子,除了安装file-loader外,我们还安装url-loader,新的例子是webpack3-6。
我们来看一下webpack的配置文件
// webpack.config.js const path = require('path'); module.exports = { entry: './a.js', output: { path: path.resolve(__dirname, ''), filename: 'bundle.js' }, module: { rules: [{ test: /\.(jpg|png)$/, use: { loader: 'url-loader', options: { limit: 1024 * 8, } } }] }, mode: 'none' };
这个配置里,我们使用url-loader处理jpg和png格式的图片,另外设置了参数limit,对于图片体积小于8KB(1024 * 8)的,我们转成base64编码的URL直接写入打包后的JS文件里。
这个例子里,我们引入了两张图片,分别是24KB的sky.jpg和4KB的chrome.png,经过url-loader处理后插入html文档里。
// a.js import img1 from './sky.jpg'; import img2 from './chrome.png'; console.log(img1); console.log(img2); var dom1 = `<img src='${img1}' />`; var dom2 = `<img src='${img2}' />`; window.onload = function () { document.getElementById('img1').innerHTML = dom1; document.getElementById('img2').innerHTML = dom2; }
<!DOCTYPE html> <html lang="en"> <head> <script src="bundle.js"></script> </head> <body > <div id="img1"></div> <div id="img2"></div> </body> </html>
我们来看一下npx webpack打包后的工程目录
我们用浏览器打开html并开启开发者工具,页面如下
可以看到,因为chrome.png小于8KB,被转成base64编码直接在打包在JS文件里,而24KB的sky.jpg仍然通过file-loader来处理。
二、file-loader与url-loader处理后的资源名称
因为url-loader处理体积大于limit值的时候,本质是使用file-loader来进行处理的,接下来包括第三小节的内容对file-loader与url-loader都适用。
之前例子里file-loader与url-loader处理后的图片是类似于be735c18be4066a1df0e48a1173b538e.jpg的格式,如果你看过本教程之前的 https://www.jiangruitao.com/webpack/hash-chunkhash-contenthash/ 一节,大概可以猜测这是一个hash值。
file-loader生成的文件默认的文件名是"[contenthash].[ext]",contenthash是资源内容hash值,ext是文件扩展名。我们可以通过设置name项来修改生成文件的名字。
file-loader除了[contenthash]和[ext]这两个常用的占位符,还有[hash]和[name],[hash]也是根据内容计算出的hash值,[name]是文件的原始名称。
三、file-loader与url-loader处理后的资源路径
file-loader默认使用output.publicPath作为资源访问地址,output.publicPath的相关内容可以参阅 https://www.jiangruitao.com/webpack/output/ 一节。
当然,也可以在file-loader的配置项options里配置publicPath参数,它会覆盖output.publicPath。
下面我们看一个例子,该例子同时包含了第二和第三小节的知识点,配套代码是 https://github.com/jruit/webpack-tutorial 的webpack3-7
// webpack.config.js const path = require('path'); module.exports = { entry: './a.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'bundle.js' }, module: { rules: [{ test: /\.(jpg|png)$/, use: { loader: 'url-loader', options: { limit: 1024 * 8, name: '[name]-[contenthash:8].[ext]', publicPath: './dist/' } } }] }, mode: 'none' };
注意,这里我们的output.path是path.resolve(__dirname, 'dist'),打包后的图片也会打到工程根目录下的dist文件夹。如果这个时候不设置publicPath,图片的访问路径就是默认的根目录,运行项目时就会发生找不到图片资源的故障。因此,我们设置图片的publicPath是'./dist/',这样就能正常在本地运行项目了。
另外,可以观察项目打包后的图片名称,现在变成了sky-be735c18.jpg,与我们在url-loader里设置的一致。
小结
通过设置limit大小,当资源体积大于limit的时候,url-loader使用file-loader来处理多媒体资源,当资源体积小于limit的时候,url-loader会计算出图片等多媒体资源的base64编码,直接打包到生成的JS或CSS文件里。我们要合理设置limit的值,不使打包后的JS或CSS文件过大,也不要设置地过小,小于1KB的资源没必要再去单独请求一次网络资源。通常会在3KB-20KB选择一个适合当前项目使用。
笔记与思考