tva
← 洞察

从 React SPA 迁移到 Astro:何时迁移以及原因

2018 年,用 React 单页应用构建企业网站是合理的架构选择。React 是当时主流的前端框架,打包工具迅速进步,相比服务器渲染方案,开发体验上的优势显得十分突出。几年后,许多同样的网站在真正影响业务成果的指标上表现欠佳:Core Web Vitals、搜索排名,以及网络条件受限的用户首次看到有效内容所需的时间。

从 React SPA 迁移到 Astro,并非全面替换框架,而是重新思考 JavaScript 在营销网站或企业网站中应处于何处,以及“每个页面都需要完整客户端运行时”这一默认假设是否曾经适用于这类网站。

为什么 React SPA 在企业网站上表现欠佳

React SPA 的性能特点源于其渲染模型。用户请求页面时,服务器返回一个引用 JavaScript 包的最小 HTML 外壳。浏览器下载这些包,解析并执行 JavaScript,渲染组件树,最后显示内容。在高速网络和缓存已就绪的情况下,这个过程可能难以察觉;但在移动网络或没有任何资源缓存的首次访问中,从请求到显示有效内容的延迟可能达到数秒。

Google 的 Core Web Vitals 指标体系让这些延迟变得具体可衡量。最大内容绘制(Largest Contentful Paint,LCP)衡量最大的可见元素何时完成渲染。对于加载首屏主视觉或首屏内容的 React SPA,这通常要等 JavaScript 执行完毕。首次内容绘制(First Contentful Paint,FCP)是一项辅助指标,不属于三项 Core Web Vitals(LCP、INP 和 CLS),也同样延后。实际中,以静态营销内容为主的 React SPA,其 LCP 经常落在“需要改进”或“较差”的区间,原因并非内容太重,而是渲染路径过于复杂。

SEO 的影响进一步加重了性能问题。搜索引擎爬虫的 JavaScript 渲染能力虽已显著提升,预先渲染的 HTML 对索引而言仍更可靠。抓取预算限制了爬虫每次访问能处理的工作量;必须执行 JavaScript 才能显示内容的页面,与 HTML 响应中立即包含内容的页面,处理方式并不相同。对于自然搜索曝光直接关系到潜在客户获取的企业网站,这一区别很重要。

Astro 改变了什么

Astro 默认输出静态 HTML(也支持按需服务器渲染,但需要主动启用)。页面在编译时构建为文件,Web 服务器可以直接提供,无需执行任何 JavaScript 就能显示内容。用户请求首页时,会收到一个完整的 HTML 文档,其中已经包含所有文字、结构化数据和元数据,浏览器可以立即渲染。

这种架构变化带来的性能收益很容易衡量。最大的内容元素已存在于初始 HTML 响应中,而非在 JavaScript 执行后才插入,因此 LCP 得到改善。FCP 也因同样的原因改善。交互性能得到改善,因为静态内容无需经历水合(hydration)阶段,让浏览器为服务器渲染的标记重新绑定事件监听器;只有下文介绍的孤岛需要水合。对于完全没有交互元素的页面——企业信息类页面中很常见——发送给浏览器的 JavaScript 接近零。

不过,现实中的企业网站大多并非纯静态。联系表单、带下拉菜单的导航,以及其他交互元素,确实需要客户端行为。此时,Astro 的孤岛架构就有了用武之地。

孤岛架构的实际应用

Astro 孤岛是一个需要客户端 JavaScript 的组件,周围则是完全静态的 HTML。Astro 不会为激活整个页面而发送完整的 React 运行时,而是只为真正需要 JavaScript 的组件发送代码。联系表单可以成为一个孤岛,下拉导航也可以成为一个孤岛。周围的标题、正文、图片和页脚仍保持静态 HTML。

这颠倒了 React SPA 的默认假设。在 React SPA 中,问题是“这个页面的哪些部分可以跳过渲染?”答案通常是没有,因为整个渲染流程都经过 React。在 Astro 中,问题变成“这个页面的哪些部分确实需要 JavaScript?”对于典型的企业网站,答案只是全部内容中的一小部分。

这一架构支持以 React、Preact、Vue、Svelte 和 Solid 等框架构建孤岛。迁移不要求重写现有 React 组件:用 React 构建的交互元素可以保留原有组件代码,继续作为 Astro 孤岛运行,周围的页面结构则改为静态内容。这种兼容性使部分迁移成为可能:负责实际交互的 React 组件得以保留,周围的营销内容不再承担完整 SPA 的开销。

何时适合使用 Astro

当以下条件成立时,迁移到 Astro 最有说服力:页面内容大多是静态的或更新不频繁;搜索曝光是主要获客渠道;网站服务于各种网络条件下的用户;交互功能集中在特定组件,而非遍布所有页面。

服务介绍、关于我们、博客文章和案例研究等企业信息网站内容,很符合这一特点。内容编写一次,反复提供给用户。每个页面的价值在于让内容高效触达用户和搜索引擎,而非动态的客户端行为。对于这种用途,React SPA 确实属于过度设计,其性能成本也真实存在。

如果应用本身确实复杂,Astro 就不那么合适,例如需要身份验证并展示个性化数据的界面、实时更新、状态繁多的用户会话,或大多数元素都需要客户端行为的密集交互界面。这些是应用的特点,而非网站的特点。实践中,网站与应用的界线往往模糊,但这正是评估迁移决策时应采用的视角。

一个实用判断方法是:如果 React SPA 的任一页面使用超过两三个交互组件,而且它们通过共享状态紧密耦合,那么它很可能已属于应用范畴,React 的组件模型仍然合适。如果页面主要是内容,只带一两个独立的交互元素,孤岛模型就更符合其架构需求。

迁移的实际步骤

完整的 React SPA 到 Astro 迁移应分阶段推进,而非一次性切换。每个阶段的目标都是达到一个可部署、优于上一版本的状态,而非进行长期重写并不断累积风险。

第一阶段是审计与分类。检查每种页面类型,对其中的交互元素进行分类。联系表单、电子邮件通讯订阅、具有 JavaScript 行为的导航菜单、交互筛选等,都是孤岛候选。不包含交互行为的内容区域,如首屏主视觉、功能列表、博客正文和团队介绍页,则是静态渲染的迁移对象。

第二阶段是基础设施配置。Astro 项目需要配置构建工具;如果是多语言网站,还需要国际化路由,并决定部署目标。Astro 的静态输出可以直接融入任何静态托管基础设施。构建过程生成文件,由服务器提供,无需应用逻辑,因此部署与缓存配置都大幅简化。

第三阶段是内容迁移。Astro 的组件模型与 React 足够相近,许多组件只需少量修改就能移植。主要变化在于:Astro 组件(.astro 文件)负责静态渲染,React 组件则保留用于交互孤岛。这种划分可以逐步引入:现有 React 组件从第一天起就能作为孤岛运行,周围结构再逐渐迁入 Astro 模板。

第四阶段是验证。应在相同条件下比较迁移前后的 Core Web Vitals,例如模拟移动网络并使用冷缓存。对于相同内容,从客户端渲染的 React SPA 迁移到 Astro 静态输出后,LCP 通常会显著改善,但改善幅度取决于迁移前的状态,应通过测量确认,而非凭空假定。SEO 的影响通常需要数周才会出现在搜索数据中,因为爬虫需要重新索引更新后的页面。

需要正视的取舍

Astro 也有自己的取舍。与提供客户端 SPA 相比,构建环节更复杂:采用静态输出时,内容变更需要重新构建并部署,而不是直接更新数据库后立即反映到页面上。对于习惯 CMS 工作流、编辑发布后几秒就能看到变更的团队,这意味着需要在内容更新时触发构建,或接受短暂的部署延迟。

复杂交互功能的开发体验也需要更仔细的设计。跨越页面上多个组件的状态,或需要在页面导航之间保留的状态,都必须显式处理;React SPA 则可通过组件上下文和客户端路由自动提供这些能力。Astro 支持视图过渡,也能通过标准浏览器 API 在孤岛之间共享状态,但相比单一 React 应用上下文,这些模式需要更有意识地设计。

这些是真实成本,而非理论上的顾虑。迁移的价值也同样真实:静态渲染带来的性能变化并非微小改善。不过,迁移决策应基于对收益和成本的诚实评估,而非假设服务器渲染在所有场景中都更优。

Astro 代表的是回归一个更简单的默认方式:向浏览器发送 HTML,只在行为需要时添加 JavaScript。对于主要目的是清晰传达内容、高效触达用户的企业网站,这比每次页面加载都必须重建 DOM 的完整客户端运行时更适合作为起点。架构应匹配网站实际做的事,而非框架的默认方式。

相关洞察

延伸阅读