基本配置
使用test+type+generator形式,匹配各种图片模式,指定解析资源类型,再规定输出文件名格式以及输出文件夹。一般来说,使用这套配置可以解决webpack项目下所有的图片引入问题。
/* config.module.rule('images') */
{
// 匹配多种图片模式
test: /\.(png|jpe?g|gif|webp|avif)(\?.*)?$/,
// 指定资源类型为 asset
type: 'asset',
// 规定好打包后生成的文件生成在 img 文件夹下
// 以图片名称+哈希值+图片格式为命名规则
generator: {
filename: 'img/[name].[hash:8][ext]'
}
}
常见的图像优化类型
- 图像压缩:减少网络上需要传输的流量
- 雪碧图:减少 HTTP 请求次
- 响应式图片:根据客户端设备情况,下发适当分辨率的图片,有助于减少网络流量
- CDN:减少客户端到服务器之间的物理链路长度,提升传输效率
图像优化:压缩
在 Webpack 生态中有不少优秀的图像压缩组件,包括:image-webpack-loader、imagemin-webpack-plugin、image-minimizer-webpack-plugin 等,以我的使用经验来看,image-webpack-loader 组件功能齐全且用法简单,更推荐使用。基本用法首先安装依赖:
yarn add -D image-webpack-loader
之后配置 Loader:
module.exports = {
// ...
module: {
rules: [{
test: /.(gif|png|jpe?g|svg)$/i,
// type 属性适用于 Webpack5,旧版本可使用 file-loader
type: "asset/resource",
use: [{
loader: 'image-webpack-loader',
options: {
// jpeg 压缩配置
mozjpeg: {
quality: 80
},
}
}]
}],
},
};
image-webpack-loader 底层依赖于 imagemin 及一系列的图像优化工具:
- mozjpeg:用于压缩 JPG(JPEG) 图片;
- optipng:用于压缩 PNG 图片;
- pngquant:同样用于压缩 PNG 图片;
- svgo:用于压缩 SVG 图片;
- gifsicle:用于压缩 Gif 图;
- webp:用于将 JPG/PNG 图压缩并转化为 WebP 图片格式。
图像压缩是一种非常耗时的操作,建议只在生产环境下开启,或者在图片进入项目之前,提前压缩。
图像优化:雪碧图
我们可以将许多细小的图片合并成一张大图 —— 从而将复数次请求合并为一次请求,之后配合 CSS 的 background-position 控制图片的可视区域,这种技术被称作“雪碧图”。在 Webpack 中,我们可以使用 webpack-spritesmith 插件自动实现雪碧图效果,首先安装依赖:
yarn add -D webpack-spritesmith
之后添加配置:
module.exports = {
// ...
resolve: {
modules: ["node_modules", "assets"]
},
plugins: [
new SpritesmithPlugin({
// 需要
src: {
cwd: path.resolve(__dirname, 'src/icons'),
glob: '*.png'
},
target: {
image: path.resolve(__dirname, 'src/assets/sprite.png'),
css: path.resolve(__dirname, 'src/assets/sprite.less')
}
})
]
};
之后,我们就可以使用 sprite.less 提供的 .sprite mixin 添加背景图:
@import (less) "./assets/sprite.less";
#main {
// 参数为原始图片文件名
.sprite(@webpack);
}
提示:雪碧图曾经是一种使用广泛的性能优化技术,但 HTTP2 实现 TCP 多路复用之后,雪碧图的优化效果已经微乎其微 —— 甚至是反优化,可以预见随 HTTP2 普及率的提升,未来雪碧图的必要性会越来越低,因此建议读者们了解作用与基本原理即可,不必深究。
图像优化: 响应式图片
Webpack 中有不少能够自动生成响应式图片的组件,例如: resize-image-loader、html-loader-srcset、responsive-loader 等,以 responsive-loader 为例,首先安装依赖:
yarn add -D responsive-loader sharp
之后,修改配置:
module.exports = {
// ...
module: {
rules: [{
test: /.(png|jpg)$/,
oneOf: [{
type: "javascript/auto",
resourceQuery: /sizes?/,
use: [{
loader: "responsive-loader",
options: {
adapter: require("responsive-loader/sharp"),
},
}],
}, {
type: "asset/resource",
}],
}],
}
};
注意,实践中我们通常没必要对项目里所有图片都施加响应式特性,因此这里使用 resourceQuery 过滤出带 size/sizes 参数的图片引用,使用方法:
// 引用图片,并设置响应式参数
import responsiveImage from './webpack.jpg?sizes[]=300,sizes[]=600,sizes[]=1024';
const Picture = function () {
return (
<img
srcSet={responsiveImage.srcSet}
src={responsiveImage.src}
sizes="(min-width: 1024px) 1024px, 100vw"
loading="lazy"
/>
);
};
上例的引用参数 './webpack.jpg?sizes[]=300,sizes[]=600,sizes[]=1024'; 最终将生成宽度分别为 300、600、1024 三张图片,之后设置 img 标签的 srcset 属性即可实现图片响应式功能。
此外,我们还能简单地通过 size 参数精确控制不同条件下的图像尺寸:
.foo {
background: url("./webpack.jpg?size=1024");
}
@media (max-width: 480px) {
.foo {
background: url("./webpack.jpg?size=300");
}
}
提示:除本文提及的基本功能外,responsive-loader 还提供了许多用于控制产物、压缩比等特性的配置项,有需要的同学可到 官网 展开阅读。