Astro 站点一旦过千页,“改个错别字”也要触发 6 分钟的全量重建,外加一次把所有 URL 都刷一遍的 CDN 失效。又慢、又费、还有风险。Astro 默认不支持真正的增量构建,但有一套实战方案能解决大部分问题。
问题背景
Astro 的构建是为冷启动确定性和速度设计的。这就导致它在热编辑场景下很慢——不管输入有没有变,每个页面都会重新生成。在大内容站频繁小改的场景里,全量重建就成了卡点,既费时又让人沮丧。解决办法不是某个神奇 flag,而是构建期裁剪、对真正不想重建的少数页面用混合渲染、再加上 CDN 层的局部刷新这三件事的组合。
判断标准
npm run build超过 90 秒。- 小改你都拖着——心里想着”等周末统一发”。
- 每次部署 CDN 全量 purge,把免费额度吃光。
- CI 时长大头是 Astro 生成阶段,不是测试或 lint。
- 你已经开始在部署前脚本里写跳过构建的 hack。
快速结论
500 页以下别折腾,直接重建。500-5000 页之间,用内容 hash + --changed 标记裁剪构建。超过 5000 页,把热边缘搬到 on-demand 或 ISR。
方案一:基于 hash 的无变化跳过
最便宜的优化是检测到没真改东西就直接跳过。把每个内容文件加上 layout 依赖一起 hash,存在 dist-cache/,下次 manifest 一致就跳过构建:
// scripts/build-if-changed.mjs
import { createHash } from 'node:crypto';
import { readdirSync, readFileSync, existsSync, writeFileSync } from 'node:fs';
const files = readdirSync('src/content/articles/en', { recursive: true })
.filter(f => f.endsWith('.mdx'));
const hash = createHash('sha256');
for (const f of files.sort()) hash.update(readFileSync(`src/content/articles/en/${f}`));
const digest = hash.digest('hex');
const last = existsSync('.build-hash') ? readFileSync('.build-hash', 'utf8') : '';
if (digest === last) {
console.log('内容无变化,跳过构建。');
process.exit(0);
}
writeFileSync('.build-hash', digest);
process.exit(1); // 让 CI 继续走构建步骤
单条错别字救不了,但能挡掉一半”只改了文档或 workflow”的 CI 运行。
方案二:热点页用混合渲染
把每天都会变的 50 个 URL(sitemap、最新列表、RSS、首页)标成 on-demand,其余继续静态。astro.config.mjs 里:
import { defineConfig } from 'astro';
import vercel from '@astrojs/vercel/serverless';
export default defineConfig({
output: 'hybrid',
adapter: vercel(),
prefetch: { defaultStrategy: 'viewport' },
});
然后在确实想走服务端渲染的路由上加 export const prerender = false;。这样一次内容改动只会让变了的那个静态页和几个 on-demand 路由失效,不动整站。
方案三:CDN 层局部失效
构建后解析 Astro 的 build manifest,找出真正变化的输出文件,只刷这些路径:
# diff 两次部署的 dist/,只 purge 变化的
git diff --name-only HEAD~1 HEAD -- 'dist/**/*.html' \
| xargs -I{} curl -X POST "https://api.cloudflare.com/.../purge_cache" \
-H "Authorization: Bearer $CF_TOKEN" \
-d "{\"files\":[\"https://yourdomain.com/{}\"]}"
大多数平台(Vercel、Cloudflare Pages、Netlify)会按内容 hash 自动做,但 Firebase Hosting 和 S3 不行,那就得自己写。
容易踩的坑
- 200 页的小站也上 hybrid,复杂度不划算,老老实实重建就行。
- 习惯性每次部署全站 purge——其实大部分平台早就按文件 hash 局部失效了。
- 自己造增量构建工具,重新实现 Astro 内部逻辑,下个 minor 版本就崩。
- 跳过构建 hash 检查,没考虑到只改 frontmatter 也会影响生成的 HTML。
- 拿 dev 模式的 HMR 当生产增量替代品——dev 模式完全绕开了 content collection 编译。
FAQ
- Astro 官方有增量构建吗: 2026 年还没有。团队在探讨(搜 “Astro Content Layer” RFC),生产环境的答案仍然是上面那套组合。
- Astro 5 的 Content Layer 能解决这个吗: 部分能。Content Layer 让数据加载更细粒度,但不改变静态生成本身。每次部署还是要全量生成。
- CI 里加持久缓存有用吗: 缓存
node_modules和.astro/能省几秒,省不到几分钟。瓶颈是页面生成,不是依赖安装。 - Firebase Hosting 能跑 hybrid 吗: 能,走 Cloud Functions 或 Cloud Run,但冷启动开销经常把好处吃掉。Hybrid 配合 Vercel、Netlify 或 Cloudflare Workers 最顺。
- 改一次内容必须刷新 sitemap 吗: 如果
lastmod对 SEO 重要就要。把 sitemap 做成 on-demand,永远反映当前数据,不用重建。