当从 S3 提供图像不再足够好时

发布: (2026年1月7日 GMT+8 23:12)
10 min read
原文: Dev.to

Source: Dev.to

请提供您想要翻译的具体文本内容,我将为您翻译成简体中文。

Background

我在 7 年前 发布了我的第一篇博客文章。我在 Medium 上写了大约一年,然后创建了 Ready, Set, Cloud。在大部分时间里,这个站点几乎没有进行过大幅改版或性能更新——它主要作为我的写作、时事通讯和播客的归宿。

我已经运营这个站点 六 年 了。我通常是那种不能长时间置之不理的人,但这个站点多年几乎没有变化。它一直运行……直到它不再运行。

性能问题

当我终于审视网站性能时,有一点显而易见:图片

  • PageSpeed Insights 显示,大尺寸、未优化的图片占据了加载时间的主要部分。
  • 图片直接作为单个文件从 S3 提供,没有格式协商,也 没有缓存

当时的这种设置并没有错。那是一个在当时相当合理的权衡:简单、低维护,对几十位读者来说“足够好”。但随着站点在内容和受众上的增长,性能期望也随之改变。直接从 S3 提供原始图片已经不再满足需求。

为什么简单的修复不足够

一种本能的反应是直接进入 S3,手动优化一堆图片。这只能治标不治本,无法解决根本问题。

  • 手动调整图片大小、转换为网页友好格式,并为每篇文章决定上传哪种尺寸 无法规模化
  • 我不想改变我的工作流程。我想继续写作、发布,然后继续前进 而不增加性能检查的层层环节

一个好的系统应该:

  1. 自动在后台优化图片
  2. 在浏览器支持时提供 WebP 等现代格式。
  3. 提供 多种图片尺寸,以免移动设备下载桌面尺寸的资源。
  4. 高度可缓存——CDN 已经在图片交付方面表现极佳。

重新思考图像处理

我意识到我并不是想要构建一个全新的图像优化工具(像过去可能会做的那样)。相反,我需要以业界标准的方式 集中优化决策

上传脚本

我使用仓库中一个小的 JavaScript 脚本将图像上传到 Ready, Set, Cloud。它:

  • 接受文件前缀。
  • 扫描本地文件夹中匹配的文件。
  • 将它们直接上传到 S3

没有 Web UI,也没有 尝试解释内容的自动化——它本身设计得很简单,我也希望保持这种方式。

自动处理

因为图像已经通过 S3 流动,系统可以在不改变工作流的情况下对上传做出响应。

  • 图像上传 会自动触发一个 Rust Lambda 函数(通过 EventBridge)。
  • 该 Lambda 将原始图像转换为 WebP生成若干标准尺寸
  • 优化后的版本会 与原始文件一起 写回 S3。

好处

  1. 确定性的优化 —— 每张图像每次都会经过相同的处理流程。
  2. 脱离关键路径工作 —— 所有这些都在 异步 进行,因此发布不会被延迟。

CDN Delivery

一旦处理完成,交付就成了下一个关注点。所有优化后的资产已经在 S3 中,但我不想在现有内容中更改 2,000+ 图像链接

Content‑Negotiation at the Edge

  • CloudFront distribution 位于 S3 存储桶前面。
  • 它在 Accept 头部中 查找 WebP 支持
  • 如果浏览器声明支持 WebP,则 CloudFront Function 会将请求路径重写为 WebP 版本。

该函数在 viewer‑request event 上运行,并在 不检查 WebP 文件是否存在 的情况下重写路径——此检查在 CloudFront 从源站获取时才会进行。重写在边缘是 一致的,并且生成的响应会被缓存,因此后续请求会遵循相同的路径。

使用 srcset 提供合适尺寸

为每张图片准备多种尺寸会自然引出下一个问题:该提供哪一种?

  • 移动屏幕不需要桌面尺寸的图片。
  • 高 DPI 显示器可以受益于更大的图片。
  • 首页的缩略图应尽可能小。

srcset 实际应用

使用 srcset 可以让 浏览器自行选择 合适的图片,依据视口大小和设备像素比。标记保持不变,无需运行时逻辑,每个客户端只下载它真正需要的内容。

![...](/images/diagram.png)

Ready, Set, Cloud 是一个 由 Hugo 生成的静态站点。添加 srcset 支持意味着 覆盖 render-image 钩子 并加入少量逻辑来生成额外的属性。

结果

我的主要目标是 降低加载时间,让网站感觉更流畅 且不在现有工作流中添加任何内容

  • 图像优化(Rust Lambda)在上传时自动运行。
  • CDN 分发(CloudFront + edge function)提供正确的格式和尺寸,全球缓存。
  • srcset 让浏览器选择最佳资源,省去手动更新链接的需求。

结果是一个更快、更具可扩展性的网站,仍然使用我一直使用的同样简单的发布流程。

性能改进

我添加了一个 IDE srcset,很高兴地看到页面负载显著下降。页面渲染更快,最大内容绘制(LCP)得到改善,整体性能也更可预测。

  • 在我的主页上,**首次内容绘制(FCP)**从 4.5 秒降至不到 1 秒
  • 桌面端和移动端的加载时间也更加一致,这一直是个持续的挑战。

SEO Bonus

意想不到的好处是,这些相同的改动也帮助了搜索引擎排名。更快的页面、更小的下载量以及积极缓存的资源都影响 Core Web Vitals。因此,即使没有明确针对 SEO,站点也因为优先考虑用户体验而更容易被爬取、索引更快,并在搜索结果中排名更高。

常见瓶颈

如果你自己搭建了博客,你可能和我一样遇到过这些性能瓶颈,这没关系。将资产从 S3 提供是一种有效的解决方案,我在站点成长的六年里它运作良好。

扩展系统

当我的约束条件改变时,我希望在不更改部署工作流的情况下扩展系统。

  • 如果你对我在此处描述的相同改进感兴趣,这个设置可以作为对现有系统的即插即用补充,在 Serverless Application Repository 中提供。
  • 如果你想深入细节或进一步改造,完整源码也可以在 GitHub 上获取。

将决策从日常工作流程中剔除

最重要的是,这旨在将关于图像格式、尺寸和缓存的一整类决策剔除出日常工作流程。只要一切就绪,性能就会自然而然地得到提升。

结束语

这既有趣又对 Ready, Set, Cloud 至关重要。我想要一个易于采用、易于移除的方案,并且能够在其他一切变化时静静地做好该做的事。

编码愉快!

Back to Blog

相关文章

阅读更多 »

机构专用固定费率网站加速工具

前10个 WordPress 站点很容易。接下来的20个悄悄打乱你的工作流程。到第30个站点时,你的工具已经在为你的机构服务,而不是你在使用它们。- 客户 A 需要...

Web 应用的浏览器缓存实用指南

介绍 什么是浏览器缓存 - 浏览器缓存 – 位于用户设备本地,重复访问时的最快路径。 - CDN / 代理缓存 – 在边缘服务器上的副本。