# 图片压缩优化
# 背景
控制器添加了很多向导功能,导致包大小从几十M膨胀到了两百多M,所以急需优化包体积。
# 优化方案
普通的文件,类似js、css,已在打包时进行压缩混淆了,没什么优化空间。
那就直接对图片进行压缩
# 方案一
通过sharp
对图片压缩
# 思路
通过递归给定的目录,找出所有图片,并针对类型进行配置,通过sharp
进行压缩。
需要注意的是,sharp
不支持svg
,需要另外使用imagemin-svgo
处理
压缩完成后,直接覆盖源文件
const sharp = require('sharp');
const imagemin = require('imagemin');
const imageminSvgo = require('imagemin-svgo');
async function handleSvg(filePath) {
const result = await imagemin([filePath], {
destination: dir,
plugins: [
imageminSvgo({
plugins: [
{ removeViewBox: false },
{ removeDimensions: true },
],
}),
],
});
console.log(result);
}
async function compressImages(dir, compressedList) {
const files = await readdir(dir);
for (const file of files) {
const filePath = path.join(dir, file);
const stats = await stat(filePath);
if (stats.isDirectory()) {
await compressImages(filePath, compressedList);
} else {
const ext = path.extname(file).toLowerCase();
if (!isImage(ext)) continue;
// svg
if (ext === '.svg') {
handleSvg();
} else {
if (compressedList[file] && compressedList[file].size === stats.size) {
// console.log(`文件 ${file} 已经压缩过,跳过处理`);
continue;
}
}
console.log(`文件 ${file} 压缩中...`);
const startTime = new Date().getTime(); // 记录开始时间
let _ext = ext.replace('.', '');
if (_ext === 'jpg') {
_ext = 'jpeg';
}
let options = {}; // sharp 配置
let formatOptions = {}; // 不同格式方法参数
// 根据文件格式, 设置不同的配置
switch (_ext) {
case 'gif':
options = {
animated: true,
limitInputPixels: false,
};
formatOptions = { colours: 128 };
break;
default:
formatOptions = { quality: 70 };
}
sharp.cache(false);
if (_ext !== 'gif') {
let image = sharp(filePath, options);
const imageBuffer = await image[_ext](formatOptions).toBuffer();
fs.writeFileSync(filePath, imageBuffer); // 覆盖源文件
}
const compressedSize = fs.statSync(filePath).size;
compressedList[file] = { size: compressedSize, originalSize: stats.size, filePath }; // 记录压缩前后文件大小
const endTime = new Date().getTime(); // 记录结束时间
console.log(`文件 ${file} 压缩完成,耗时 ${endTime - startTime} 毫秒`);
}
// }
}
}
# 缓存
每次压缩时,记录文件名及大小,下次再执行压缩时通过对比日志,对已压缩过的进行跳过,达到缓存的效果。
# 注意点
sharp包需要在.npmrc
中配置镜像地址
# 缺点
脚本写在项目里,且sharp
包十分难装,影响打包速度,还可能失败。
并且对gif的压缩效果不理想,压缩颜色范围可以减小体积,但是会导致颜色失真,影响效果
所以,该方案pass
# 方案二
最终选用的该方案
基于开源项目https://github.com/leibnizli/hummingbird 改造
该项目使用了sharp
进行裁剪、imagemin
进行压缩,可以对图片、视频等进行压缩
并且是通过electron
打包成软件包,可安装使用,解决了imagemin
包在内网安装难的问题
当然,对于gif来说,压缩效果同样不理想。所以对于gif我们另外处理。
# 改造点
由于该项目会对js、css压缩,这是我们不需要的,所以在代码中需屏蔽掉。
gif的压缩等级调到最大
# 流水线
之所以不在流水线中做压缩,原因有以下:
imagemin
包不好装- 每次都压缩图片会拖慢打包速度
所以决定用单独的工具进行压缩
# 缓存
参照方案一的缓存方案,实现功能
# 安装
目前只提供windows版本
下载地址:
# 开发
# 依赖包
由于依赖十分难装,在内网装不上,有需要的可前往``下载
# 打包
打包需要用到的electron的三方包,需手动下载后放在电脑缓存中
# gif压缩
gif的压缩通常就以下几个方向:
- 尺寸
- 颜色范围
- 帧率
尺寸要适配弹窗,不能改
颜色范围降低会产生色差,也不能改
帧率,可以降到合理范围,但是目前所有三方包都不支持自动改帧率,所以决定使用screenToGif
软件手动抽帧,实测帧率在5~8帧范围内,看起不影响效果。之前很多都是30帧,对于引导图来说,完全用不上。
# 优化效果
优化前:219M
优化后:127M
减小包体积42%