如果你使用 Next.js,有两种方式来提供 WebP 图片:让 next/image 在运行时自动转换, 或者在部署前预先转换为 WebP 并直接提供预转换文件。两种方式都能在浏览器中显示 WebP,但性能 特性差异很大。本文详细分析每种方式的工作原理,以及何时应该选择哪种方式。
next/image 按需转换的工作原理
当浏览器通过 Next.js 图片优化管道请求图片时,服务器在第一次请求时会执行以下操作:
- 从磁盘读取源图片或从远程 URL 获取
- 将图片解码为原始像素缓冲区
- 以请求的质量和尺寸重新编码为 WebP
- 将结果写入磁盘缓存(通常是
.next/cache/images/) - 将 WebP 响应流式传输到浏览器
对于后续请求(相同 URL、相同宽度、相同质量),Next.js 从磁盘读取缓存的 WebP 并跳过重新编码。缓存以 URL + 宽度 + 质量 + 格式为键,因此同一图片的 400px 和 800px 渲染 分别缓存。
冷启动惩罚
每个图片变体的第一次请求都很慢。以下是中等配置云 VM(2 vCPU)上的典型编码时间:
| 源图片 | 尺寸 | 首次请求延迟 | 缓存命中延迟 |
|---|---|---|---|
| 2 MB JPEG | 3000×2000 → 800px | ~340 ms | ~4 ms |
| 5 MB PNG | 4000×3000 → 1200px | ~820 ms | ~6 ms |
| 500 KB JPEG | 1200×900 → 400px | ~90 ms | ~3 ms |
在 Serverless 部署(Vercel、AWS Lambda)中,每次实例启动都会发生冷启动。高流量页面的缓存 很快变热;低流量或长尾页面在服务器冷却时会向每个新访问用户提供缓慢的首次渲染。
预转换 WebP:静态方法
另一种方法是运行构建时转换步骤——使用 sharp、cwebp 或 Picovert 的 PNG to WebP 转换工具——并将生成的 .webp 文件提交到仓库或上传到 CDN。然后在标记中直接引用 .webp:
<img src="/images/hero.webp" width={1200} height={630} alt="Hero" />
或者,如果你仍想使用 Next.js 的响应式缩放但不需要格式转换,可以将 .webp 文件 传给 next/image——优化器检测到 WebP 输入后会跳过重新编码,仅在需要时执行缩放。
对比总结
| 因素 | next/image 按需转换 | 预转换 WebP |
|---|---|---|
| 首次请求延迟 | 慢(编码开销) | 快(静态文件) |
| 后续请求 | 快(磁盘缓存) | 快(CDN/静态) |
| 响应式缩放 | 自动(srcset) | 手动或自定义 |
| 格式协商 | 自动(AVIF/WebP/JPEG) | 每种格式手动处理 |
| 部署复杂度 | 无额外步骤 | 需要构建步骤 |
| Serverless 冷启动 | 受影响 | 不受影响 |
| 存储成本 | 每个变体缓存增长 | 构建时固定 |
何时使用 next/image 按需转换
- 用户生成内容——图片在运行时上传,构建时未知,无法预转换。
- 大型图片库——数百到数千张产品图片,预转换所有图片会给 CI 增加数分钟。
- 流量集中在热门页面——热缓存使冷启动在实践中很少发生。
- 需要 AVIF 支持——
next/image为每个浏览器协商最佳格式。 构建时 AVIF 转换很慢;向支持的浏览器提供 AVIF 并以 WebP 作为回退,没有优化器很难实现。
何时预转换为 WebP
- 营销/落地页——图片数量少、流量大,每毫秒 TTFB 都很重要。
- 使用 CDN 的 SSG(静态网站生成)——构建后,WebP 文件无需服务器处理, 直接从边缘节点提供。
- 冷启动不可预测的 Serverless 部署——消除编码延迟保证一致的首字节时间。
- 不常变更的图片——Logo、Hero 图片、OG 缩略图等,构建步骤成本可以忽略。
混合方法
大多数生产 Next.js 应用受益于结合两种策略:将关键的首屏图片(Hero、LCP 候选)小集合 预转换为 WebP,让 next/image 处理动态或不太重要的图片长尾。这样可以在重要 图片上实现接近零的 LCP 延迟,同时避免对整个图片目录进行大规模构建开销。
总结
next/image 的按需转换对大多数应用来说是正确的默认选择。但对于关键渲染路径上的 图片——Hero 图片、首屏缩略图、OG 图片——预转换为 WebP 可以完全消除冷启动惩罚,无论服务器 状态如何都能提供一致的快速首次渲染。两种策略相互补充。