Skip to content
0
/ Rendering/Island Architecture
6/1/2026
3.3m
AI 摘要

Island 架构按岛 hydrate 减 JS;以 Astro、Qwik 对比 TTL/FCP 优化。

Island Architecture ​

在 SSR 一章中,我们有说到,请求返回的 HTML 中,会有 JS 脚本用于 hydrate,如下是 Vite + Vue 的 SSR 中返回的一个示例页面:

<!DOCTYPE html>
<html lang="en">
  <head>
    <script type="module" src="/@vite/client"></script>
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <title>Vite + Vue + TS</title>
  </head>
  <body>
    <div id="app"><!--[--><div data-v-7a7a37b1><a href="https://vitejs.dev" target="_blank" data-v-7a7a37b1><img src="/vite.svg" class="logo" alt="Vite logo" data-v-7a7a37b1></a><a href="https://vuejs.org/" target="_blank" data-v-7a7a37b1><img src="/src/assets/vue.svg" class="logo vue" alt="Vue logo" data-v-7a7a37b1></a></div><!-- <HelloWorld msg="Vite + Vue" /> --><!--]--></div>
    <!-- 用于 hydrate 的客户端脚本 -->
    <script type="module" src="/src/entry-client.ts"></script>
  </body>
</html>

这个脚本会将 div#app 下面的元素进行注水激活,这使得我们可以先看到页面的内容,减少 FCP,而又不缺失页面的交互性

但上面的场景也存在优化空间,因为这段 JS 的执行也可能会影响到 DOM 的渲染,影响页面的 TTL

实际上,我们并不需要 JS 一次性激活页面全部的交互,如果我们可以选择我们想要激活的部分(组件)进行 hydrate,剩余部分需要的时候再 hydrate,就可以提高页面的性能。

我们把页面拆成多个部分,每个部分被称作 island,也就是岛屿(孤岛),这就是 island 架构

Astro
​

比较有代表性的是 Astro 框架。对待每个组件都如一个岛屿,我们可以选择激活的时机甚至是激活的框架,这也就是为什么我们能在 Astro 中使用除了官方的 .astro 之外,还可以使用 vue、react、svelte 等多种丰富的框架

举个例子,譬如我们想要我们的组件在视口可见的时候激活,在 Astro 的形式:

// index.astro file
---
import ReactComponent from "./ReactComponent"

---

<ReactComponent client:visible />

Qwik
​

Qwik 也使用了 island 的概念,不过比 Astro 更近一步。不需要手动设置 hydrate 的指令

将 JS 的执行时间还往后推迟了

Delay execution of JavaScript as much as possible.

How qwik works ​

qwik 工作的基本原理

创建组件

假设我们写了一个 qwik 组件,而且我们的组件看起来像这样:

export const Main = component$(() => {
  const state = useState({
    message: 'hello',
  })

  return (
    <input
      value={state.message}
      onInput$={e => state.message = e.target.value}
    />
  )
})
组件处理

以完全不同的方式加载组件。在服务端,JS 路径被编码在 HTML 中,所以他们不会被浏览器下载,直到它们被需要

<div on:input="./path-to-input-hander.js">
  <input value="hello" />
</div>
监听和激活

需要用一个轻量的 JS 代码进行激活,以便于在用户动作触发的时候(这个例子是触发 input 事件),下载 JS 代码并执行。代码和下面的类似:

<script>
  for (const event of events) {
    document.addEventLister(event, e => {
      const target = e.target.closet(`on:${event}`)
      if (target) import(target.getAttribute(`on:${event}`))
        .then(mod => mod.default(e))
    })
  }
</script>

Released under the MIT License.