Islands 不是 Web Components:两种「按需加载」根本不是一回事

Islands 在构建期决定哪里需要 JS、什么时候水合;Web Components 在运行时给浏览器一个自带行为的元素。把它们当成同一件事,会选错工具。

这两个词经常出现在同一段话里,好像都是「只在需要时才加载」的方案。它们其实在不同层面上工作:一个管构建与加载时机,一个管封装与运行时。

Islands:构建期的切分与水合时机

Astro 的 island 是构建期概念。每个交互组件被切成独立 chunk,页面其余部分是纯 HTML:

<SearchBox client:idle />
<Comments client:visible />

client:idle / client:visible 决定水合时机(主线程空闲后、进入视口时),而不是决定「要不要下载」。没有水合指令的组件、以及页面上所有静态部分,最终一行 JS 都不发。

Web Components:运行时的元素

自定义元素是浏览器的原生能力:你注册 customElements.define('x-counter', ...),页面上 <x-counter> 就有了行为,带上 Shadow DOM 还能自带样式隔离。它不需要构建工具、不绑定框架,任何页面上都能用。

但它不是懒加载机制。定义脚本要么一开始就加载,要么你自己在某个时刻 import() 它 —— 而这一步没有任何约定,浏览器不会因为你插入了一个 <x-counter> 就去下载对应的定义。

那 <my-counter> 看起来怎么那么像 island

因为渲染结果确实一样:都是页面上一个自定义标签。区别在谁把它变成活的。island 是框架在浏览器里挂载(createApp 或 hydrate)后渲染出来的;Web Component 是浏览器读到标签名就去查注册表。前者依赖构建产物,后者依赖已加载的定义脚本。

本站为什么不用 Web Components

两个原因。一是样式:视觉方向靠 :root 上的令牌驱动,而 Shadow DOM 里的选择器要跨边界就只剩自定义属性继承和 ::part,用起来比直接写 SCSS 啰嗦。二是分工:本站的「按需加载」需求已经被 island 覆盖,再加一套组件注册机制只会多一条加载路径。

真正适合 Web Components 的场景是跨框架复用:一个组件要同时出现在 Vue 页面、老 jQuery 后台和别人的静态站里,或者要把一个 widget 嵌进第三方页面。

Islands 解决「什么时候加载」,Web Components 解决「谁来封装」。同一个页面上两者可以同时存在。

← 返回文章列表

评论

…