服务端岛屿

作者
Fred Schott
Matthew Phillips

这是我们“Astro 的未来”系列的第三部分,涵盖了我们计划在 2024 年为 Astro 推出的三大功能。本文介绍了服务端岛屿(Server Islands):一种新的岛屿架构原语,它允许你交付静态、CDN 缓存的 HTML 页面外壳,并注入动态内容。

2021 年,Astro 开创了一种名为岛屿的新前端架构。岛屿之所以独特,是因为它允许 Astro 自动从你的页面中剥离所有未使用的 JavaScript,从而提供更快的性能,而无需强迫你在开发时放弃你喜欢的 UI 组件(React、Svelte、Vue 等)。

但前端性能并非你在 Web 开发中会遇到的唯一性能问题。你如何将网站交付给用户,其影响甚至可能比你交付的内容更大,而开发者常常被迫做出一个艰难的选择:追求性能,还是个性化?

性能: 将页面作为静态 HTML 提供,并积极缓存。你将无法为用户个性化页面,但静态 CDN 部署带来的性能优势、成本节约和简易性是无与伦比的。

个性化: 将页面作为动态 HTML 提供,按需渲染。这会迫使你的请求通过可能远在半个地球之外的数据中心,从而降低性能,并增加你未能通过谷歌核心 Web 指标的风险。然而,动态响应所解锁的控制和个性化水平又让人难以拒绝。

性能和个性化不应相互排斥。我们相信岛屿架构同样能解决这个问题,我们目前正在开发一项新功能,力求为你带来两全其美的体验:服务端岛屿。

服务端岛屿

服务端岛屿是我们正在为 Astro 探索的一种新原语,它建立在我们现有的岛屿前端架构之上。你定义服务端岛屿的方式与定义客户端岛屿相同,但使用的不是 client:* 指令,而是新的 server:defer 指令。

<UserButton server:defer />

这会告诉 Astro 在初始响应中跳过渲染该组件,并将其渲染“推迟”到稍后进行。这使你可以将带有初始占位符内容的静态页面缓存在 CDN 之后。当动态 HTML 加载完成后,它会用延迟渲染的 HTML 结果替换页面上的服务端岛屿。

你可以在下面的原型中看到其运行情况。静态页面会立即加载大部分页面内容(在本例中,在 Vercel 上运行耗时 21 毫秒)。然后,动态的延迟组件 HTML 会单独渲染,当延迟渲染完成后,Astro 会将所有内容重新拼接在一起。

从概念上讲,这与 React、Solid 等框架中的 Suspense 概念类似,但关键区别在于延迟岛屿是作为单独的 HTTP 请求渲染的。我们特意避免在单个响应中同时流式传输静态内容岛屿,以便为你选择的 CDN 简化处理。

A diagram showing the server island population parts of the page from the server.

通过将所有动态 HTML 移至延迟的服务端岛屿中,你将获得两全其美的效果:

  • 性能: 一个即时加载的、缓存在全球 CDN 上的静态 HTML 页面外壳。
  • 个性化: 动态内容可注入到页面上你想要的任何位置。

服务端岛屿并非适用于所有用例。有些页面可能需要如此多的动态内容,以至于在服务器上渲染整个页面仍然是合理的选择。其他网站可能仍希望从 API 端点以 JSON 格式获取动态内容。

然而,我们相信对于内容驱动型网站中的绝大多数个性化内容而言,服务端岛屿是有意义的。我们看到用 Astro 构建的网站通常会在页面上混合动态和静态内容。对于这些目前无法利用 CDN 缓存的网站,服务端岛屿很可能会带来巨大的性能提升。

后续步骤

我们正处于此功能的设计阶段,并正在思考不同实现的权衡取舍,但原型开发已在进行中。

请在不久的将来关注 Astro 对服务端岛屿的实验性支持。我们通常会在新功能稳定之前通过实验性标志发布它们,这让我们的用户有充足的时间来试用新的 API 并提供反馈。如果你想更早地参与进来,请查阅 RFC 并立即参与讨论。