关于 islands-architecture
面向以静态内容为主的网站开发者的岛屿架构指南,讲解如何保留静态 HTML,并仅为独立交互组件加载和水合脚本。该方式适用于重视首屏加载与 SEO 的页面,不适合高度交互的应用。
主要功能
- 01将静态区域与交互区域分离
- 02仅水合独立交互组件
- 03减少发送到客户端的 JavaScript
- 04静态渲染支持 SEO
- 05列举 Astro、Marko 等实现
适用场景
- 01为博客文章添加社交按钮
- 02在商品页中嵌入图片轮播
- 03为静态交易列表添加筛选器
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ patternsdev/ skills --skill islands-architecture安装后在 Claude Code 中输入/islands-architecture确认已加载。
详细介绍
Islands 架构
目录
适用场景
- 适用于主要为静态、只需少量交互功能的网站(博客、产品页面、新闻网站)
- 如果想减少发送到客户端的 JavaScript 量,这种架构会很有帮助
- 如果 SEO 和快速初始页面加载与选择性交互同样重要,请使用这种架构
说明
- 分别识别每个页面中的静态区域和动态区域
- 使用支持 Islands 架构的框架,例如 Astro、Marko 或 Eleventy
- 使用
client:visible或类似指令独立对交互组件进行水合 - 让页面的大部分内容保持为静态 HTML,JavaScript 成本为零
详情
加载和处理过多的 JavaScript 会损害性能。然而,即使是主要为静态的网站,通常也需要一定程度的交互和 JavaScript。我们讨论过静态渲染的各种形式,这些形式可用于构建应用,在以下两方面之间寻求平衡:
- 与客户端渲染(CSR)应用相当的交互性
- 与 SSR 应用相当的 SEO 优势
SSR 的核心原则是在服务端渲染 HTML,并附带必要的 JavaScript,以便在客户端重新水合。重新水合是指服务器渲染 UI 组件后,在客户端重新生成其状态的过程。由于重新水合需要付出代价,SSR 的各种形式都试图优化重新水合过程。这主要通过对关键组件进行部分水合,或在组件渲染时流式传输来实现。然而,以上技术最终发送的 JavaScript 总量仍然相同。
Islands 架构这一术语由 Katie Sylor-Miller 和 Jason Miller 推广,用于描述一种旨在减少 JavaScript 发送量的范式:在原本静态的 HTML 上,以可独立交付的“交互岛”形式提供交互功能。Islands 是一种基于组件的架构,它将页面视为由静态岛和动态岛组成的分区。页面的静态区域是纯粹的非交互式 HTML,无需水合。动态区域则由 HTML 和脚本组成,能够在渲染后自行重新水合。
动态组件岛屿
大多数页面都是静态内容和动态内容的组合。通常,页面由静态内容构成,其中点缀着可独立隔离的交互区域。例如:
- 博客文章、新闻报道和组织主页包含文本和图片,也包含社交媒体嵌入内容、聊天等交互组件。
- 电商网站上的产品页面包含静态产品说明以及指向应用其他页面的链接。图片轮播、搜索等交互组件则分布在页面的不同区域。
- 典型的银行账户详情页包含静态交易列表,并通过筛选器提供一些交互功能。
静态内容没有状态,不会触发事件,也无需在渲染后重新水合。渲染后,动态内容(按钮、筛选器、搜索栏)必须重新绑定事件。DOM 必须在客户端重新生成(虚拟 DOM)。重新生成、重新水合和事件处理功能都会增加发送到客户端的 JavaScript 代码。
Islands 架构便于在服务器端渲染包含所有静态内容的页面。不过在这种情况下,渲染后的 HTML 会为动态内容包含占位符。动态内容占位符中包含独立的组件小部件。每个小部件都类似于一个应用,会结合服务器渲染的输出和用于在客户端水合应用的 JavaScript。
渐进式水合采用自顶向下的页面水合架构。页面负责控制各个组件的调度和水合。在 Islands 架构中,每个组件都有自己的水合脚本,该脚本会异步执行,不受页面上其他脚本的影响。某个组件出现性能问题时,不应影响其他组件。
实现 Islands
Islands 架构借鉴了不同来源的概念,并力求将它们以最佳方式结合起来。基于模板的静态站点生成器,例如 Jekyll 和 Hugo,支持将静态组件渲染到页面中。大多数现代 JavaScript 框架也支持同构渲染,让你能够使用相同的代码在服务器和客户端渲染元素。
Jason 的帖子建议使用 requestIdleCallback() 实现组件水合的调度方式。可以将静态同构渲染和组件级部分水合的调度集成到框架中,以支持 Islands 架构。因此,框架应当:
- 支持在服务器上以零 JavaScript 静态渲染页面。
- 支持通过静态内容中的占位符嵌入独立的动态组件。每个动态组件都包含自己的脚本,并且可以在主线程空闲时使用 requestIdleCallback() 自行水合。
- 允许在服务器上同构渲染组件,并在客户端进行水合,以便在两端识别出相同的组件。
框架
如今,不同的框架都能够支持 Islands 架构。值得关注的包括:
-
Marko:Marko 是一个开源框架,由 eBay 开发并维护,旨在提升服务端渲染性能。它通过结合流式渲染与自动局部水合来支持 Islands 架构。HTML 和其他静态资源一准备就绪,就会立即流式传输到客户端。自动局部水合可使交互组件自行完成水合。水合代码仅会随交互组件一起发送,这些组件可以在浏览器中更改状态。它是同构的,Marko 编译器会根据代码的运行位置(客户端或服务端)生成优化后的代码。
-
Astro:Astro 是一个静态站点构建器,可以将使用 React、Preact、Svelte、Vue 等其他框架构建的 UI 组件生成轻量级静态 HTML 页面。需要客户端 JavaScript 的组件会连同各自的依赖项单独加载。因此,它内置了局部水合功能。Astro 还可以根据组件何时变为可见来延迟加载组件。
-
Eleventy + Preact:Markus Oberlehner 展示了如何使用 Eleventy——一个静态站点生成器,以及可进行局部水合的同构 Preact 组件。它也支持延迟水合。组件本身会通过声明式方式控制自身的水合。交互组件使用
WithHydration包装器,以便在客户端进行水合。
请注意,Marko 和 Eleventy 早于 Jason 提出的 Islands 定义,但包含了支持该架构所需的一些特性。不过,Astro 是基于该定义构建的,并且原生支持 Islands 架构。
示例实现
以下是使用 Astro 实现的示例博客页面。页面 SamplePost 导入了一个交互组件 SocialButtons。该组件通过标记插入 HTML 中的指定位置。
// Component Imports
import { SocialButtons } from '../../components/SocialButtons.js';
<html lang="en">
<head>
<link rel="stylesheet" href="/blog.css" />
</head>
<body>
<div class="layout">
<article class="content">
<section class="intro">
<h1 class="title">Post title (static)</h1>
<br/>
<p>Post sub-title (static)</p>
</section>
<section class="intro">
<p>This is the post content with images that is rendered by the server.</p>
<p>The next section contains the interactive social buttons component which includes its script.</p>
</section>
<section class="social">
<div>
<SocialButtons client:visible></SocialButtons>
</div>
</section>
</article>
</div>
</body>
</html>
// SocialButtons.js
import { useState } from "preact/hooks";
export function SocialButtons() {
const [count, setCount] = useState(0);
const add = () => setCount((i) => i + 1);
const subtract = () => setCount((i) => i - 1);
return (
<>
<div>{count} people liked this post</div>
<div align="right">
<button onclick={add}>Like</button>
<button onclick={subtract}>Unlike</button>
</div>
</>
);
}
SocialButtons 组件是一个 Preact 组件,其中包含 HTML 及相应的事件处理程序。
该组件会在运行时嵌入页面,并在客户端进行水合,从而使点击事件按预期运行。
Astro 能够清晰地分离 HTML、CSS 和脚本,并鼓励采用基于组件的设计。使用此框架可以轻松安装并开始构建网站。
优缺点
Islands 架构融合了多种渲染技术的理念,例如服务端渲染、静态站点生成和部分水合。采用 Islands 架构可能带来以下一些好处。
-
性能:减少发送到客户端的 JavaScript 代码量。发送的代码仅包含交互组件所需的脚本,远少于重建整个页面虚拟 DOM 并对页面所有元素进行水合所需的脚本。JavaScript 体积更小,自然意味着页面加载速度更快,交互时间(TTI)也更短。
-
**SEO:**由于所有静态内容都在服务器上渲染,因此页面对 SEO 友好。
-
**优先呈现重要内容:**用户几乎可以立即看到关键内容(尤其是博客、新闻文章和产品页面)。交互所需的次要功能通常会在用户浏览关键内容后逐步加载。
-
**无障碍性:**使用标准的静态 HTML 链接访问其他页面,有助于提升网站的无障碍性。
-
**基于组件:**这种架构具备基于组件的架构的所有优点,例如可复用性和可维护性。
尽管有这些优点,这一概念仍处于起步阶段。支持有限也带来了一些缺点。
- 开发者只能选择使用少数现有框架之一,或自行开发 Islands 架构。将现有网站迁移到 Astro 或 Marko 需要投入额外精力。
- 除了 Jason 最初发布的文章,关于这一理念的讨论很少。
- 新框架声称支持 Islands 架构,因此很难筛选出适合自己的框架。
- 这种架构不适用于社交媒体应用等高度交互的页面,因为这类页面可能需要数千个岛屿。
Islands 架构是一个相对较新的概念,但凭借其性能优势,很可能会逐渐受到关注。它强调使用 SSR 渲染静态内容,同时通过动态组件支持交互,并将对页面性能的影响降至最低。我们希望未来这一领域能有更多参与者,并提供更丰富的实现选项。