在前端体积里,图片往往是「重量级选手」——一张未压缩的 PNG 可能好几百 KB,比整个 JS bundle 还大。而 webpack 默认只会原样搬运图片,不会做任何压缩。手动用工具逐张压缩既麻烦,又难以在团队里保持一致。Image Minimizer 就是把图片压缩自动化、纳入构建流程的方案。
一、为什么需要它
默认情况下,webpack 的 asset modules 只负责「输出」图片:
{
test: /\.(png|jpe?g|gif|svg)$/i,
type: 'asset/resource',
generator: { filename: 'images/[hash][ext][query]' },
}
它做了三件事:解析引用、复制文件、生成路径。但压缩这一步完全没有。原始图片多大,产物里就多大。
这会带来几个问题:
- 首屏变慢:图片体积直接决定加载时间,是影响 LCP 等指标的关键。
- 手动压缩难维护:让每个人上线前手动压图,既不可靠也无法自动化。
- 多余元数据:相机、设计工具导出的图片里常带无用信息(Exif、多余色板),白白占体积。
- 格式老旧:明明可以用 WebP / AVIF 等更省体积的格式,却只能一直用 JPG / PNG。
而 image-minimizer-webpack-plugin 可以在构建阶段自动完成无损压缩、有损压缩,甚至格式转换。
二、Image Minimizer 是什么
image-minimizer-webpack-plugin 是 webpack 5 生态下的图片压缩插件。它挂载在 optimization.minimizer 上,在压缩阶段处理 asset modules 产出的图片,原理是调用底层的压缩实现:
- imagemin:经典方案,基于各种格式专用工具(
imagemin-mozjpeg、imagemin-pngquant、imagemin-svgo等)。 - sharp:基于
libvips,速度快、支持 WebP / AVIF 等现代格式的转换。 - squoosh:基于 Google 的 Squoosh,压缩质量高,但速度较慢。
它和 asset modules 的分工很清晰:
| 角色 | 负责 |
|---|---|
| asset modules | 解析引用、输出文件、生成路径 |
| image-minimizer | 压缩文件、转换格式、去除元数据 |
两者配合,才构成完整的图片处理链路。
三、怎么用
1. 安装
以 imagemin 无损压缩为例,需要同时安装插件和对应的压缩工具:
npm install image-minimizer-webpack-plugin imagemin --save-dev
npm install imagemin-gifsicle imagemin-jpegtran imagemin-optipng imagemin-svgo --save-dev
2. 配置 asset modules
图片必须先被 webpack 当作 asset 输出,压缩插件才能处理它:
module.exports = {
module: {
rules: [
{
test: /\.(jpe?g|png|gif|svg)$/i,
type: 'asset/resource',
generator: { filename: 'images/[hash][ext][query]' },
},
],
},
};
注意:不要把图片设成
asset/inline(或让asset的maxSize把图片内联成 base64)。内联后的图片不是独立文件,压缩插件无法处理。
3. 配置 minimizer
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin');
module.exports = {
optimization: {
minimizer: [
'...', // 保留 webpack 默认的 JS 压缩
new ImageMinimizerPlugin({
minimizer: {
implementation: ImageMinimizerPlugin.imageminMinify,
options: {
plugins: [
['gifsicle', { interlaced: true }],
['jpegtran', { progressive: true }],
['optipng', { optimizationLevel: 5 }],
['svgo', { plugins: [{ name: 'preset-default' }] }],
],
},
},
}),
],
},
};
其中 '...' 用于保留 webpack 内置的 TerserPlugin,否则 JS 压缩会被替换掉——这是配置 optimization.minimizer 时最容易犯的错。
4. 无损 vs 有损
- 无损压缩(lossless):不改变像素,只优化编码、去元数据。下面的
imageminMinify属于这一类。 - 有损压缩(lossy):在可接受画质损失下换取更小体积,例如
pngquant、降低 JPG 质量。
有损压缩通常改用 sharp,配置更直观:
npm install sharp --save-dev
new ImageMinimizerPlugin({
minimizer: {
implementation: ImageMinimizerPlugin.sharpMinify,
options: {
encodeOptions: {
jpeg: { quality: 80 },
webp: { quality: 80 },
png: { quality: 80 },
},
},
},
})
sharp 基于 libvips,速度远快于 imagemin,且不需要为每种格式单独装包,推荐优先考虑。
5. 转换成 WebP / AVIF
除了压缩,还可以顺带生成现代格式。用 generator 在保留原图的同时额外产出一份 WebP:
new ImageMinimizerPlugin({
generator: [
{
type: 'asset',
preset: 'webp',
implementation: ImageMinimizerPlugin.imageminGenerate,
options: {
plugins: ['imagemin-webp'],
},
},
],
})
这样使用方可以通过 <picture> 等方式按浏览器支持情况选择格式,进一步降低体积。
6. 只处理部分图片
如果只想压缩某类图片,用 test 限定范围:
new ImageMinimizerPlugin({
test: /\.(jpe?g|png)$/i,
minimizer: {
implementation: ImageMinimizerPlugin.sharpMinify,
options: {
encodeOptions: { jpeg: { quality: 80 } },
},
},
})
四、注意事项
- 只有在
minimize开启时才生效。生产模式默认开启;开发模式下optimization.minimize为 false,图片不会被压缩。 - 图片必须被引用到。压缩的是 webpack 输出(emit)出来的资源,如果没有被 import 或写在 CSS 里,就不会进入构建流程。纯拷贝的静态图片应改用其它方式处理。
- 别忘了
'...'。配置optimization.minimizer时不写'...',会把默认的 JS 压缩器覆盖掉,导致 JS 不再压缩。 - 构建会变慢。有损压缩(尤其 imagemin + optipng)耗时明显,建议配合缓存。
- 不要重复压缩。源图应保留原始高质量版本,压缩只在构建阶段做;反复压缩有损图片会持续劣化画质。
- 内联图片不会被处理。如前述,base64 内联的图片不经过压缩插件。
五、完整配置示例
const path = require('path');
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin');
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/[name].[contenthash:8].js',
assetModuleFilename: 'assets/[hash][ext][query]',
clean: true,
},
module: {
rules: [
{
test: /\.(jpe?g|png|gif|svg)$/i,
type: 'asset/resource',
parser: {
// 不内联,保证图片是独立文件,可被压缩
dataUrlCondition: { maxSize: 0 },
},
generator: { filename: 'images/[hash][ext][query]' },
},
],
},
optimization: {
minimize: true,
minimizer: [
'...', // 保留默认 JS 压缩
new ImageMinimizerPlugin({
test: /\.(jpe?g|png|gif|svg)$/i,
minimizer: {
implementation: ImageMinimizerPlugin.sharpMinify,
options: {
encodeOptions: {
jpeg: { quality: 80, progressive: true },
png: { quality: 80 },
webp: { quality: 80 },
gif: {},
},
},
},
}),
],
},
};
六、替代思路
image-minimizer-webpack-plugin 会在每次构建时压缩图片,图片多时较慢。实践中也常见这些替代方案:
- 独立构建脚本:用
sharp写一个npm run optimize-images脚本,压缩结果提交或单独部署。 - 图片 CDN:由 CDN 按需实时压缩和格式转换(如带
?format=webp参数),构建阶段零负担。 - 构建前预处理:在提交前用工具批量压缩,构建只负责搬运。
选哪种,取决于项目对「构建时自动化」和「构建速度」的权衡。
小结
| 问题 | 答案 |
|---|---|
| webpack 默认压缩图片吗 | 不,只原样搬运 |
| 谁来压缩 | image-minimizer-webpack-plugin |
| 压缩实现 | imagemin(经典)/ sharp(快,推荐)/ squoosh |
| 怎么配置 | 放在 optimization.minimizer,保留 '...' |
| 前提 | 图片作为独立 asset 输出,不能内联 |
| 生效时机 | minimize 开启时(生产模式) |
一句话:asset modules 负责把图片搬出来,Image Minimizer 负责把图片压下去。 把压缩交给构建流程,既能减小产物体积,也能免去手动压图的繁琐,是图片优化中最省心的一环。