Astro Island架构实现原理

什么是Islands架构

Islands架构类似于微前端架构,但Islands主要是为了优化页面性能和用户体验,而微前端是为了解耦不同业务模块。

island

为什么要使用Islands

  1. 可以优先展示或者水合重要内容,比如电商商品详情页可以优先展示和水合商品主图、商品描述、购买按钮。
  2. 浏览器加载的js变少,能够提升TTI。

使用

Astro有很多指令表示一个组件是在服务端渲染还是客户端渲染、渲染时机。

directives description priority
client:load 页面加载后立即水合 high
client:idle 在requestIdleCallback中进行水合 medium
timeout 最大等待时间后水合 low
client:visible 进入视口后水合 low
client:media 媒体查询后水合 low
client:only 不进行服务端渲染 low
server:defer 按需渲染

可以使用这个astro的模版快速搭建一个demo

使用client:load标记组件为Island组件,并且高优先级水合

1
<BuyNowButton client:load onClick={handleClick}>点击购买</BuyNowButton>

原理

通过Astro的compiler将astro代码编译成如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { render as $$render, createAstro as $$createAstro, createComponent as $$createComponent, renderComponent as $$renderComponent } from "astro/compiler-runtime";
import BuyNowButton from "../components/BuyNowButton";
import { withBase } from "../utils";
const $$Astro = $$createAstro();
const Astro = $$Astro;
const $$Index = $$createComponent(($$result, $$props, $$slots) => {
const Astro2 = $$result.createAstro($$Astro, $$props, $$slots);
Astro2.self = $$Index;

return $$render`${$$renderComponent($$result, "BuyNowButton", BuyNowButton, {
"client:load": true,
"client:component-hydration": "load",
"client:component-path": "/with-nanostores/src/components/BuyNowButton",
"client:component-export": "default",
"data-astro-cid-j7pv25f6": true
})}`;
}, "/with-nanostores/src/pages/index.astro", void 0);

在renderComponent中会将标记为client:load的组件渲染成

1
<astro-island uid="Z1xkbrp" component-url="/src/components/BuyNowButton.tsx" component-export="default" renderer-url="/node_modules/.vite/deps/@astrojs_preact_client-dev__js.js?v=ec7158f6" props="{&quot;data-astro-cid-sckkx6r4&quot;:[0,true]}" client="load" before-hydration-url="/@id/astro:scripts/before-hydration.js" opts="{&quot;name&quot;:&quot;BuyNowButton&quot;,&quot;value&quot;:true}" server-render-time="1.461416999999983" await-children="" client-render-time="1"><aside hidden="" class="_container_jwp5b_1"><p>Your cart is empty!</p></aside></astro-island>

服务端返回的就是上面的html,并且会返回astro-island.js文件,该文件注册astro-island自定义元素,
该元素在connectCallback后获取astro dom上的component-url、renderer-url(hydrator水合器)和props。最后await hydrator(<Component {…props}/>)渲染组件

参考

https://jasonformat.com/islands-architecture/
https://docs.astro.build/zh-cn/concepts/why-astro/#_top