从Docusaurus到Astro 5.x:Islands架构如何重塑文档站的构建与性能
去年年初我把一个维护了两年的技术文档站从 Docusaurus 3.x 整体迁到了 Astro 5.x。最初触动我的其实是构建速度——内容不到 400 篇生产构建却要两分半CI 上每次改错别字都要等一轮。真正迁完回头看收获比预期大得多不仅构建时间从 148 秒压到了 38 秒页面 Lighthouse 分数也从长期徘徊的 68 分直接跳到 97 分以上而这一切的核心就是 Astro 5.x 的 Islands 架构。这篇不是一份“照抄配置就行”的清单而是一次真实迁移过程的记录。它适合那些正被 Docusaurus 的大体积 JS 和慢构建困住的文档维护者也适合对 Islands 架构感兴趣但一直没动手的博客作者。如果你正站在“要不要迁”的十字路口希望这篇能帮你把账算清楚。1. 先说说为什么要迁Docusaurus 3.x 的几个痛点1.1 性能卡在输送链路而不是内容Docusaurus 本质上是 React 单页应用的思路只不过打包时改成了多页输出。这意味着每个页面——哪怕是纯文字、一张图都没有的 API 参考页——都必须加载整套 React 运行时和页面 bundle。我实测过很多次首页 JS 传输体积稳定在 75KB gzip 左右请求数 18 个起步移动端 Lighthouse 常年 68 分上下。这里有个很反直觉的点你的内容再轻输送链路在那儿摆着性能天花板就锁死了。打个比方你只是给一个房间送几本书却每次都要开动整栋楼的中央空调。Docusaurus 的插件生态、主题机制、搜索方案都成熟但“每个页面都要水合hydrate整套 React 运行时”这个架构模型决定了它的性能瓶颈不是内容质量而是输送方式。1.2 构建时间越来越难忍另一个痛点是构建速度。Docusaurus 底层是 webpack 5这套打包链路在内容量变大的时候会非常难受。我有段时间开了它自家的 experimental faster 实验模式用 swc-loader 做转译确实能把构建时间从 3 分多钟压到 2 分半左右但也就是“还能忍”的水平离“流畅”差远了。更麻烦的是增量更新。文档站最大的特点是定向修改多——今天改个错别字明天加一节 FAQ每次 CI 却要全量打包一遍。webpack 的缓存机制在这种场景下表现一般经常改一行字也要等一分半。团队里写文档的人开始抱怨“改个字比写个字还久”这就是逼我下决心的直接导火索。1.3 Islands 架构到底改变了什么Astro 5.x 的 Islands 架构解决的就是上面两个问题。它默认输出纯静态 HTML整个页面是一篇“海洋”只有真正需要交互的组件才是“岛屿”。这些岛屿通过client:load、client:idle、client:visible之类的指令按需加载 JS没写指令的组件就永远是纯 HTML一个字节的脚本都不产生。这对文档站是降维打击。我们绝大多数文档页没有交互需求只有少数组件——代码块复制按钮、版本切换器、评论区——需要 JavaScript。Islands 架构让这些组件精准水合而不是全站水合。构建速度的提升也很好理解没有全站 SPA 的逻辑构建器不必把所有页面打包进一个共享的 JS bundle静态页直接输出 HTML 就行真正有交互的组件才需要进模块图。再加上 Astro 基于 Vite/Rollup生产构建的并行度和文件级缓存都比 webpack 那套老链路舒服。2. 迁移方案定调Starlight 还是从零搭2.1 为什么选 Starlight 而不是自己从空模板开始Astro 有两种路线空模板自己组织页面或者直接用官方文档主题 Starlight。我的取舍很直接——内容以文档为主体侧边栏、目录、上一页/下一页这些文档站基础能力不值得重复造轮子所以我选了 Starlight。Starlight 默认自带搜索底层走 Pagefind、国际化目录结构、移动端折叠目录、编辑此页链接。这套东西对标 Docusaurus 的 preset-classic开箱即用不用自己写页面骨架。唯一要注意的是Starlight 的定位是“文档站”如果你的站还有大量营销落地页、复杂首页可能需要空模板 Starlight 混用或者干脆另起一个 Astro 实例。我们这种情况比较单纯内容全部是文档 少量博客Starlight 完全能覆盖。2.2 迁移前的内容盘点与 URL 规划迁移前最重要的一件事不是写代码而是把现有 URL 全部列出来。我先把 Docusaurus 的 sitemap 导出来逐条比对目标站点的路由结构标注“哪些路径可以原样保留”“哪些必须重定向”。这一步不能省。URL 一旦改动搜索引擎收录、外链、书签全部受影响。我们大部分路径用 Astro 的redirects配置就能解决配置里支持destination加status301 跳转非常干净。但重定向只是兜底方案能不换路径就不换路径迁移后新链接和老链接能对上是最好的结果。2.3 技术债清单哪些带走哪些必须重写把现有文件分三类处理比直接复制粘贴靠谱得多能原样带走的Markdown/MDX 正文内容、图片等静态资源、大部分设计规范思路。内容本身没有框架耦合直接复制到src/content/docs/目录基本就能识别。必须转换的frontmatter 字段、MDX 里的 Docusaurus 内置组件Tabs、Admonition、主题相关的 CSS 变量、搜索配置、侧边栏定义。建议重写的纯展示性质的 React 组件比如手风琴、折叠面板、按钮组这些在 Astro 里用原生 HTML 或.astro组件重写能砍掉大量 JS。这个清单做出来后迁移工作量心里就有数了。我当时估算内容搬迁占用 60% 时间组件重写占 20%搜索和侧边栏等配置调整占剩下的 20%。实际做完也差不多是这个比例。3. 核心迁移实操记录3.1 初始化项目与配置对标初始化直接用官方模板然后补上 React 集成和 MDX 集成npm create astrolatest -- --template starlight npx astro add react npm install astrojs/mdx astrojs/sitemap这里astro add react会自动改astro.config.mjs把 React 集成挂上。我的配置文件长这样// astro.config.mjs import { defineConfig } from astro/config; import starlight from astrojs/starlight; import react from astrojs/react; import mdx from astrojs/mdx; import sitemap from astrojs/sitemap; export default defineConfig({ site: https://docs.example.com, integrations: [ starlight({ title: 产品文档中心, editLink: { baseUrl: https://github.com/example/docs/edit/main/, }, sidebar: [ // 侧边栏配置在 3.4 节展开 ], }), react(), mdx(), sitemap(), ], redirects: { /docs/old-path/: /docs/new-path/, }, });对标 Docusaurus 的docusaurus.config.jsStarlight 把主题、侧边栏、社交链接全收进starlight()这个集成配置里结构更集中。Docusaurus 的 navbar、footer 在 Starlight 里对应nav和footer配置别照着原来字段名死找。3.2 文档内容迁移frontmatter、MDX 与代码块内容文件复制到src/content/docs/后第一个拦路虎是 frontmatter 不兼容。Docusaurus 的sidebar_position在 Starlight 里不被识别需要换成order或者干脆在侧边栏配置里手工排序。我建议只在需要精细控制的地方用order一般情况让 Starlight 按目录结构自动生成就行省去大量手工配置。字段映射大致是这样Docusaurus 字段Astro/Starlight 对应title/description原样保留sidebar_positionorder或移到sidebar配置数组slug原样保留注意 Starlight 会自动加/docs前缀tags原样保留配合自定义页面展示keywords原样保留MDX 正文还有一堆需要正则处理的语法迁移主要是提示块。Docusaurus 用的是:::note这种四个冒号的 admonitionStarlight 用的是::note三个冒号的 aside 语法。好在差异很小写个脚本批量替换即可。代码块的 Shiki 高亮参数也有差异Docusaurus 通过js titlexxx.ts给代码块加标题Astro 的 Shiki 同样支持这套写法但行号高亮的语法从 Docusaurus 的highlight插件换成了 Shiki 的{1,3-5}这种花括号写法。1. MDX 文件编译报错。 大概率是 frontmatter 里还有 Docusaurus 特有字段没有清掉。用npx astro sync生成内容类型后在编辑器里先让 schema 校验跑一遍比等构建报错再回头找快得多。页面整体朝向的 CSS 丢失、暗色模式失灵。 重点检查customCss文件里的变量命名。Starlight 用的是--sl-color-*自定义属性体系原来 Docusaurus 的--ifm-color-*不会自动映射。全局搜一下这两个前缀逐个替换。搜索索引太大导致 Pagefind 卡顿。 在public/pagefind目录不存在的情况下首次构建会生成索引如果文档量大可以单独跑npx pagefind并加--exclude-selector排除侧边栏、页脚等噪内容。跳转代码片段锚点失效。 Docusaurus 自动给每个标题生成 idAstro 的 Shiki 也做类似处理但缩进后的列表项 id 生成规则不同建议 URL 里带锚点的地方都要实际点一遍。这些坑的共同特点都是新旧框架的“默认值”差异表面上配置文件能对上实际渲染路径差着一大截。按我自己的经验找一台干净的机器跑一遍astro build把错误信息攒齐了再统一处理比一个个试要高效得多。5.2 你最好提前知道的几个细节第一个细节是迁移顺序。强烈建议先跑通一个最小 Starlight 项目并发布到预览环境挑三四个代表性页面做样板顺便把 CSS 变量、侧边栏分组、代码高亮主题调到位。然后按“文档 → 博客 → 国际化 → 重定向”的顺序逐块迁移每块上线验证后再做下一块。我们当时保留旧站三个月新站稳定后再切流量压力小很多。第二个细节是astro sync的使用习惯。Astro 5.x 的 Content Layer 和 TypeScript 类型打通后astro sync会生成内容集合的类型定义。如果你用 VS Code 或编辑器有 TS 支持建议把它写进predev钩子里这样前端页面引用集合数据时类型错误可以在编辑器里提前暴露不用等 CI。第三个细节是关于 Islands 架构的执行粒度。很多人迁完发现自己一个 client 指令都没加因为所有组件都是纯展示的这很正常但要注意别为了“用上架构”强行给组件加水合。Islands 的价值在于“按需”不是“每个互动都必须 JS”。能用details解决的手风琴千万别为了用 React 去写一个 20KB 的折叠组件。6. 写在最后迁移后的维护体验说实话迁移前我最担心的是“换框架工作量太大”结果实际操作下来内容搬迁本身一点都不难真正花时间的是对组件颗粒度的重新思考。几个月的维护下来最大的感受是文档团队不再关心“页面是怎么渲染的”这件事了他们只负责写 Markdown构建和性能问题几乎消失。偶尔需要新互动组件优先用.astro写静态输出只有确实需要复杂状态才引入 React 岛。这里再分享一个小技巧Astro 的client:idle并不是唯一的懒加载选择代码块复制按钮我用的是client:visible也就是滚动到它附近才加载比 idle 更激进一些。如果你的页面里岛不多这个细节可能省不了多少但页面一多微优化叠加起来效果很明显。另外Starlight 对多版本文档的支持依然是弱项。如果你有大量版本化文档需求迁之前一定要想好目录组织方案别等到内容几千篇才回头重构路径。至少在我们这个规模下“子目录 侧边栏分组”已经足够不必追求和 Docusaurus 版本文档完全一致的产品形态。工具没有完美的Astro 5.x 也有它的取舍但至少对于以内容为核心的文档站Islands 架构把“渲染成本”和“实际需求”重新对齐了。这篇记录里所有数据都来自我维护的站点不同项目会有浮动参考思路即可。如果你也正准备从 Docusaurus 跳出来建议先拿一个不重要的子站跑一遍验证完再动主干。