Astro 5 升 6 完整记录:48 页博客真实迁移数据,官方"2x 提速"在小博客上不成立

Astro 6.0 在 2026 年 3 月发布正式版,关键卖点是用 Vite 7 + Environment API 重写开发服务器、Cloudflare Workers 一等公民支持、实验性 Rust 编译器。官方博客的标题用了”2x faster”,社区文章则普遍说”小博客 1-2 小时就能迁移完”。

但这两个数字都是对别人的总结,不是对我自己博客的。我把博客(48 页内容、Astro 5.16.6、自部署 nginx)升到了 Astro 6.3.1,记录全过程:实际改了什么、构建快了多少(剧透:没快)、什么坏了又怎么修。这篇文章是给和我配置接近的小博客(< 100 页 + 已用 Content Collections)一份”诚实的迁移参考”。

升级前的项目基线

升级前的关键配置(确认这些匹配,你的迁移路径会接近我):

astro:           5.16.6
@astrojs/rss:    4.0.14
@astrojs/sitemap: 3.6.0
@astrojs/check:  0.9.6
node:            v25.6.0
内容数量:         48 篇 published + 100+ draft
集成:             仅 sitemap
内容管理:         Content Collections API(已是 v5 风格)
样式:             Tailwind CSS(@tailwindcss/vite 插件)
markdown 增强:    remark-toc、remark-collapse、Shiki 转换器

构建命令:

astro check && astro build && pagefind --site dist && cp -r dist/pagefind public/

整个项目从 AstroPaper 主题改造而来,没有 SSR、没有 Astro Actions、没有 server endpoints——纯静态生成。这种配置在 Astro 用户里很典型,迁移压力小。

升级前先打基线

升级前测一次构建耗时,作为对比基准:

time npm run build
# 输出尾部
# Finished in 1.033 seconds (pagefind)
# npm run build 2>&1  15.37s user 19.09s system 75% cpu 45.766 total

Astro 5 基线:总耗时 45.77 秒,CPU 时间 15.37 秒。

如果你的博客也要升级,强烈建议先记录这个数据——不然升完只会觉得”好像差不多”,没有具体对比就没法判断官方宣传是真是假。

升级实操

第一步:建分支

git checkout -b upgrade-astro-6

绝对不要在 main 上直接升级。Astro 6 虽然兼容性不错,但 Content Collections 大改了,万一你用的还是老 API,回滚会很痛。

第二步:选择升级方式

Astro 给了官方升级工具:

npx @astrojs/upgrade

它会列出受影响的包、问你确认、再批量升。但有一个隐性问题——它进入交互模式后,在自动化脚本环境里会卡住(我用 Claude Code 跑的,需要确认按钮无法点)。

我的解法:直接用 npm 指定版本号升:

npm install astro@6.3.1 \
  @astrojs/rss@4.0.18 \
  @astrojs/sitemap@3.7.2 \
  @astrojs/check@0.9.9

升级用 30 秒,比官方工具更省心。

第三步:第一次构建——配置错误

npm run build

第一次构建就报错:

[config] Astro found issue(s) with your configuration:
! Invalid or outdated experimental feature.
  Check for incorrect spelling or outdated Astro version.
  See https://docs.astro.build/en/reference/experimental-flags/

原因:Astro 5 时代用的几个 experimental flag,在 6.0 已经毕业到正式 API。我的 astro.config.ts 里有两个:

// Astro 5 写法(已废弃)
experimental: {
  preserveScriptOrder: true,
  fonts: [
    {
      name: "Google Sans Code",
      cssVariable: "--font-google-sans-code",
      provider: fontProviders.google(),
      fallbacks: ["monospace"],
      weights: [300, 400, 500, 600, 700],
      styles: ["normal", "italic"],
    },
  ],
},

修改成 Astro 6 的正式写法:

// Astro 6 正式 API
// preserveScriptOrder 已是默认行为,直接删除
// fonts 提升到顶层
fonts: [
  {
    name: "Google Sans Code",
    cssVariable: "--font-google-sans-code",
    provider: fontProviders.google(),
    fallbacks: ["monospace"],
    weights: [300, 400, 500, 600, 700],
    styles: ["normal", "italic"],
  },
],

重新构建,通过。整个修改过程不到 2 分钟。

实测:构建性能数据

升级完跑了两次构建,对比 Astro 5 基线:

指标Astro 5.16.6Astro 6.3.1(冷启动)Astro 6.3.1(热缓存)
构建总时间45.77s57.43s47.70s
CPU 时间15.37s22.64s14.80s
页数4848(输出 107 文件)48
dev server 启动未测7154ms

结论很反直觉

  1. 冷启动反而慢 25%(45.77s → 57.43s)—— Vite 缓存重建、依赖重新优化
  2. 热缓存几乎持平(45.77s → 47.70s,差 1.93 秒,可能是误差)
  3. CPU 时间略微改善(15.37s → 14.80s,约 3.7%)—— 这才是真实的”计算效率”提升

官方博客标的”2x faster”是怎么来的?看了一下他们的 benchmark:

  • 用的是 1000+ 页的 Docs 站点
  • 启用了 Astro 6 的实验性 Rust 编译器
  • 对比的是 Astro 5 默认 Go 编译器

我没启用 Rust 编译器(experimental,生产风险高),项目只有 48 页——所以官方的提速幅度在我这个规模上根本不会出现。

这不是 Astro 6 的问题——它就不是为小博客做性能优化的。它的真正卖点在别处。

Astro 6 真正的卖点(小博客也能受益的)

1. dev 与 prod 环境一致

Vite Environment API 让 dev server 跑你真实部署的 runtime。以前 Astro 5 时代经常遇到的”开发能跑、部署到 Cloudflare Workers 就坏”,6.0 之后从根本上解决——开发时跑的就是 Workers runtime。

我自己博客部署到自建 nginx,不存在 runtime 不一致问题,这条对我没收益。如果你打算从 Vercel / Netlify 迁到 Cloudflare Workers,Astro 6 是这件事的最佳时机。

2. Cloudflare Workers 一等公民

Cloudflare 在 2025 年完成对 Astro 的收购后,Astro 6 第一次把 Workers 当作一等部署目标:

  • @astrojs/cloudflare 适配器升到了原生 Workers Runtime(不再用 Pages Functions 模拟)
  • 静态 + SSR 混合模式开箱即用
  • KV、R2、Durable Objects 通过 cloudflare: namespace 直接调用

对小博客的实际意义:Cloudflare 免费层支持的 100k 请求/天 + 全球边缘节点,对独立博客几乎免费。这是 Astro 6 之后开始变得真的可用。

3. fonts API 稳定

之前我博客的 Google Sans Code 字体加载是 experimental.fonts 配置——每次 Astro 小版本升级都担心被改坏。6.0 之后这个 API 是稳定的,未来 18 个月内不会破坏。

实际收益:心理收益 > 性能收益——但对长期维护来说很重要。

4. 实验性 Rust 编译器(如果你需要的话)

Astro 6 引入了 Rust 写的 .astro 编译器(取代之前的 Go 实现)。官方数据:

  • 大型项目(1000+ 页)构建提速 4-10x
  • 小型项目几乎无感

启用方法:

experimental: {
  rustCompiler: true,
}

(实际 flag 名 rustCompiler,类型 boolean——我从 node_modules/astro/dist/types/public/config.d.ts 直接确认的。Astro 6.3.1 实测可用。)

我没启用。原因:48 页项目用不上、experimental 阶段不稳定、回滚成本不值。如果你有 500+ 页的 docs 站点,这个值得开启

不太显眼但会”咬你”的几个变更

升级文档里有些细节藏得深,但真实项目里会遇到:

Zod 4 升级——schema 验证 API 变了

Astro 6 升级到 Zod 4,部分字符串验证 API 从 z.string().xxx() 移到了顶层 z.xxx()

// Astro 5 / Zod 3
const schema = z.object({
  email: z.string().email(),
  url: z.string().url(),
});

// Astro 6 / Zod 4
const schema = z.object({
  email: z.email(),  // 顶层 z.email()
  url: z.url(),      // 顶层 z.url()
});

我的 content.config.ts 没用到 .email() / .url(),逃过一劫。但如果你的 frontmatter schema 里有,必须改。错误信息选项也从 { message: '...' } 改成 { error: '...' }

astro:schema 被替换

// Astro 5
import { z } from "astro:schema";

// Astro 6
import { z } from "astro/zod";

Astro.glob() 被移除

如果你的项目还在用 Astro.glob() 加载文件,必须改:

// 旧:Astro.glob()
const posts = await Astro.glob("../content/blog/*.md");

// 新:getCollection 或 import.meta.glob
const posts = await getCollection("blog");
// 或者纯文件加载
const files = import.meta.glob("../content/blog/*.md", { eager: true });

我的项目早就迁到 Content Collections 了,这条没踩坑。

Content Layer API 是必选

如果你的 content.config.ts 还是老版 Content Collections(直接定义 schema 不用 loader),Astro 6 会拒绝构建。新写法:

import { defineCollection, z } from "astro:content";
import { glob } from "astro/loaders";  // 关键:loader

const blog = defineCollection({
  loader: glob({ pattern: "**/[^_]*.md", base: "./src/data/blog" }),
  schema: z.object({
    // ...
  }),
});

我的项目已经是这个写法(AstroPaper 主题在 Astro 5 时代就升过),所以没改。

Vite 7 插件兼容性

Astro 6 用 Vite 7。如果你有自定义 Vite 插件,要验证它们兼容性。社区报告 Tailwind CSS 的 @tailwindcss/vite 在 Vite 7 下有 TS 类型问题,但运行时正常——我的项目里那个 @ts-ignore 注释就是这个原因——我升完 Astro 6 后这个警告不再出现,原来的 @ts-ignore 可以尝试移除(如果 TS 还报错就保留)。

部署后的 SEO 影响(AdSense 重审窗口期重点)

我博客这两周刚好在 AdSense 重审窗口期(被拒后等 6/16 重新申请),最关心的就是”升级会不会让 Google 重新爬取整个站点、引起 SEO 评分震荡”。

实测下来观察:

  • URL 结构没变:sitemap 里所有 URL 与升级前完全一致
  • 静态输出基本不变:HTML diff 主要是 Astro client router 的脚本名 hash 变了,结构内容相同
  • 响应头一致:之前加的 HSTS / X-Frame-Options / Cache-Control 都正常工作
  • Google Search Console 没出现新 404 / 5xx

也就是说:对 Google 来说,这次升级几乎无感。这是 Astro 静态生成模式的优势——内容输出稳定,框架变更不会传染到 SEO 层。

如果你也在敏感的 AdSense / SEO 窗口期,Astro 5 → 6 是安全的升级,前提是你的项目已经在 v5 形态(Content Collections + 无 Astro.glob)。

决策建议

按真实数据给你一份决策表:

我的项目是?
├── 100 页以下的纯静态博客
│     └── 升 → 30 分钟完工,零迁移风险
├── 100-500 页的内容站点
│     └── 升 → 1-2 小时(主要花在 Vite 插件验证)
├── 500+ 页 + 用 Astro.glob / 老 Content Collections
│     └── 暂缓 → 先迁到 v5 风格 Content Layer,再升 v6
├── 用了大量自定义 Vite 插件
│     └── 暂缓 → 在 staging 验证 1 周
├── Vercel / Netlify 上跑得好的 SSR 项目
│     └── 看你是否计划迁到 Cloudflare Workers
└── 已经在 Cloudflare Workers + 想要原生支持
      └── 强烈推荐升 → Astro 6 把这个体验做对了

结论:升不升?

我的实际感受:

  • 性能:48 页这种规模无明显提升,官方”2x faster”在小项目上是营销话术
  • 维护成本:30 分钟改两处配置,无回滚
  • 未来收益:Cloudflare Workers 整合、Vite Environment API 带来的 dev/prod 一致性,是中长期值得的
  • 风险:几乎为零(前提是项目已经是 v5 风格)

结论:48 页博客该不该升?该升。但别期待性能飞跃,是为了下一个 18 个月不被破坏性变更折腾。

如果你也是 AstroPaper 主题或类似的小型静态博客用户,这次升级路径几乎和我一样。把这篇文章当一份”已经踩过坑的迁移记录”参考就好。


延伸阅读