1336 字
7 分钟
0 次浏览
构建低成本的博客图片处理方案:全链路优化实践指南

这套方案是我在博客图片处理上的一次完整实践总结。无论用 Astro、Hexo、Hugo 还是其他静态站点生成器,都能参考这里的思路,优化图片性能。从压缩、上传、云端处理到前端适配,全链路自动化,省心高效。

NOTE

写这篇文章的一些思考可以在 Github Issue - AVIF 格式引入与浏览器兼容性探讨 #3 查看

效果展示#

先来看一下整体流程:

graph LR A[原始图片] --> B[压缩上传] B --> C[R2存储桶] C --> D[Worker 处理] D --> E[Cloudflare Images 转换] E --> F[多格式回存 R2] F --> G[博客 picture 适配] style A fill:#e1f5fe style G fill:#c8e6c9

背景#

图片质量和加载速度一直是博客体验的关键。尤其面向国内用户,既要保证清晰度,又要让页面秒开,还得控制流量和成本。经过多次探索,逐步形成了这套低成本、高兼容的图片处理方案。

核心需求#

  • 性能优先:图片体积尽量小,加载速度尽量快
  • 兼容性强:各种浏览器都能正常显示
  • 自动化流程:写作到发布全自动,无需手动处理
  • 成本可控:优先选用免费或低价服务

技术选型#

  • 图片上传:PicGo
  • 图片存储:Cloudflare R2
  • 图片处理:Cloudflare Images API
  • 自动化:Cloudflare Worker
  • 图片分发:主要依赖 WebP Cloud Services,结合 R2 存储
  • 前端适配:多框架通用方案

适用场景#

方案适用于 Astro、Hexo、Hugo、WordPress 及其他静态站点,核心思路通用,前端实现可灵活调整。

架构设计#

1. 图片上传层#

PicGo 配合 Cloudflare R2,搭建免费图床。具体细节可参考:从零开始搭建你的免费图床系统 (Cloudflare R2 + WebP Cloud + PicGo)

2. 云端处理层#

我编写了一个 Worker 来进行图像处理。访问 Worker URL 或调用 API 时,会自动生成 AVIF、WebP、JPG 等多种格式,无需人工干预。支持健康检查和队列,保证自动化和可靠性。

主要流程:

  • Worker 检查图片扩展名,决定是否处理
  • 立即返回处理状态,异步执行图片任务
  • 从 R2 拉原图,上传到 Cloudflare Images,生成多格式后再存回 R2

相关代码和部署细节可以在 GitHub 仓库 查看,有兴趣可以参考源码和实现思路。

3. 前端适配层#

不同博客框架下,图片适配方式略有不同,但核心思路一致。

核心实现代码#

前端图片适配的实现,Astro 下可以通过配置 Sharp 服务自动生成多种图片格式。比如在 astro.config.mjs 里:

export default defineConfig({
image: {
service: {
entrypoint: "astro/assets/services/sharp",
config: {
formats: ["avif", "webp", "jpeg"],
quality: {
avif: 80,
webp: 80,
jpeg: 85,
png: 85,
},
progressive: true,
},
},
},
});

如果需要更智能的图片处理和降级,可以用自定义组件。比如 ImageWrapper.astro,会自动遍历格式优先级,生成 <source> 标签,并根据图片来源动态降级。部分核心逻辑如下:

---
// ...参数处理与导入省略...
async function generateImageFormats(image: ImageMetadata) {
const formats = [
{ name: "avif", type: "image/avif" },
{ name: "webp", type: "image/webp" },
{ name: "jpeg", type: "image/jpeg" },
{ name: "png", type: "image/png" },
];
const availableFormats = [];
for (const format of formats) {
try {
const optimizedImage = await getImage({
src: image,
format: format.name as any,
width: image.width,
height: image.height,
});
availableFormats.push({
src: optimizedImage.src,
format: format.name,
});
} catch (error) {
// ...错误处理省略...
}
}
// ...降级逻辑与返回省略...
}
---
// ...渲染部分省略...

完整组件代码和详细逻辑可以参考:ImageWrapper.astro 源码

对于 Hexo、Hugo 等静态博客,直接用 <picture> 标签即可实现多格式适配:

<picture>
<source srcset="https://your-r2-domain/images/photo.avif" type="image/avif">
<source srcset="https://your-r2-domain/images/photo.webp" type="image/webp">
<img src="https://your-r2-domain/images/photo.jpg" alt="Photo description" loading="lazy">
</picture>

或用 JS 自动化批量处理图片标签:

function optimizeImages() {
const images = document.querySelectorAll('img[data-optimize]');
images.forEach(img => {
const picture = document.createElement('picture');
picture.innerHTML = `
<source srcset="${img.src.replace(/\.\w+$/, '.avif')}" type="image/avif">
<source srcset="${img.src.replace(/\.\w+$/, '.webp')}" type="image/webp">
${img.outerHTML}
`;
img.parentNode.replaceChild(picture, img);
});
}
TIP

建议结合自身需求和技术栈,探索适合自己的图片优化方案。可以参考 <picture> 标签的多格式适配思路,也可以尝试插件、自动化脚本或第三方服务。每个框架都有不同的扩展方式,灵活调整才能获得最佳效果。

兼容性与探索#

AVIF 格式虽然高效,但并非所有浏览器都支持。实际测试发现,部分老旧浏览器甚至新版本也有兼容性问题。采用 <picture> 标签,优先提供 AVIF,其次 WebP,最后 JPEG 或 PNG,浏览器会自动选择支持的格式,兼容性和体验兼顾。

也尝试过 avif.js、WebAssembly 等方案,但维护和兼容性不理想。最终还是觉得 <picture> 标签最简单可靠。图片优化方面,Sharp 虽然强大,但图片放仓库会导致仓库膨胀,影响构建和拉取效率。现在远程图片都用 webp.se 或 Cloudflare R2 分发,省心高效。

性能优化策略#

渐进式加载#

所有图片都用 lazy loading 和异步解码:

<Image
loading="lazy"
decoding="async"
// ... 其他属性
/>

格式优先级#

现代浏览器支持度排序:

  1. AVIF(最优)
  2. WebP
  3. JPEG/PNG(兜底)

参考资料#

构建低成本的博客图片处理方案:全链路优化实践指南
https://mc.mimeng.top/posts/general/blog-image-solution/
作者
梦辰
发布于
2025-08-05
许可协议
CC BY-NC-SA 4.0