← 返回随记
折腾·

博客图片自动优化管线搭建记

前端性能优化工具

一图顶千字,但 23 张就是灾难

浮光博客比较吃视觉。首页全屏 Hero 背景、Bento 卡片、每日一图轮播、随记页背景、文章封面……算下来一共 23 张高清插画,有不少是 4K 甚至更高分辨率的 PNG。某天我突然意识到这个事情,打开开发者工具看了下——好家伙,光首页就可能下载 8MB 的图片。最大的单张(一张灯塔插画)6.1MB,比整个 Next.js 框架的 JS bundle 还大。

这得治。

方案选型

常规思路有三种:

  1. 上 CDN + 实时转换:像 Cloudflare Images 或 imgix,上传原图后按 URL 参数动态出不同尺寸/格式。好处是不折腾,坏处是要钱,而且博客是纯静态自部署,不想引入外部依赖。

  2. 手动压图:每次找到新图,用 Squoosh 或 PS 手动转 WebP、出几档尺寸,再改代码引用。太累,而且删图时容易忘清理。

  3. 构建时自动处理npm run build 时跑一个脚本,扫描 public/images/,自动转 WebP、出多尺寸、生成模糊占位符。跟静态导出的思路完全契合。

我选了 3。思路简单:把 sharp 塞进构建流程,就像 Webpack 打包 JS 一样"打包"图片。

核心设计

按图片目录制定优化策略,不是一刀切:

  • Hero 背景、随记背景quality: 82sizes: [480, 768, 1280, 1920, 2560, 3840]。最初用 CSS background-image(不支持 srcset),现已改为 <img> + object-fit: cover,浏览器按视口自动选图。手机 480w(~30KB),4K 屏最高 3840w(~300KB)。
  • 每日一图、文章封面quality: 80-82,出 480w / 768w / 1200w / 1920w 四档。<img> + srcset + sizes 让浏览器按需选。手机 375px 视口下只加载 480w 版本(~25KB),桌面才上全尺寸。
  • 每张可显示图都生成模糊占位符:20px 宽 + 高斯模糊 + base64 data URI,塞进 HTML。页面打开瞬间就有个模糊的影子,不用对着白屏发呆。

组件侧统一走 getImage(path) 拿回所有信息——srcsrcSetblurDataURL——调用方不需要关心是 dev 还是 build、有没有优化产物。

增量构建与孤儿清理

每次 build 都重压 23 张图显然浪费。脚本用源文件的 mtime 做增量判断,没改过的直接跳过。实测改动一张图后 rebuild,只重压那一张。

删图也省心。脚本会把 images-optimized/ 下所有优化产物反推回源文件路径——如果源文件已经没了,自动删掉残留并清理空目录。删一张图,零残留。之前有个 Windows 路径分隔符的坑(path.join 出反斜杠导致 Map.has() 匹配失败,72 个文件全被当成孤儿),现在已经修好了。

效果

优化前优化后
图片总量~50.5MB~8.4MB
最大单张6.1MB PNG507KB WebP
Hero 背景1.7MB88KB
首页首次图片载荷~8MB~500KB

手机端效果最明显——之前打开首页要等十几秒图才出来,现在几乎是秒加载。

一点感想

做这个优化的过程中有个体会:好的工具链应该让正确的事情毫不费力。加一张图,往文件夹里一扔就行,不需要改配置、不需要记步骤。删一张图也是直接删,构建时自动清理。如果每次加图都要手动跑三四个命令,迟早会乱掉。

这套图片管线现在成了博客构建流程的一部分,默默服务。希望它能静悄悄地运行很久,久到我都忘了它的存在——那才是最好的工具。