回到所有文章

Astro Islands:让网页回归轻盈

3 分钟阅读

当我们打开一篇文章时,真正想得到的通常很简单:文字清晰、加载迅速、阅读不被打断。

但很多网页在展示第一段文字之前,需要先下载一整套运行时,初始化组件,建立状态,再重新计算已经由服务器生成过的内容。

Astro 给出了一种更朴素的选择:先把内容交给读者,只为需要交互的部分发送 JavaScript。

把 HTML 放回中心

Astro 组件默认在构建时或服务器端渲染为 HTML。没有客户端指令的框架组件,也不会自动把框架运行时发送到浏览器。

---
import Article from '../components/Article.astro';
import LikeButton from '../components/LikeButton.jsx';
---

<Article />
<LikeButton client:visible />

文章本身是静态 HTML。只有点赞按钮进入视口之后,才会加载它需要的交互代码。这些独立的交互区域,就是“岛屿”。

选择合适的加载时机

Astro 的客户端指令让我们对交互的成本保持清醒:

指令 什么时候加载 适合的场景
client:load 页面加载时 首屏需要立即使用的交互
client:idle 浏览器空闲时 非关键但需要较早可用的功能
client:visible 进入视口时 评论区、图表、交互实验
client:media 匹配媒体查询时 仅在特定屏幕尺寸启用的组件

需要注意,这些指令用于 React、Vue、Svelte 等客户端框架组件。普通 .astro 组件中的原生脚本可以直接用 <script> 编写,不需要给它添加客户端指令。

内容应该有自己的结构

博客不只是一个页面列表。标题、日期、标签和草稿状态,都属于内容本身。

使用 Content Collections,可以在构建时验证这些信息,并为查询结果提供类型提示:

import { defineCollection } from 'astro:content';
import { glob } from 'astro/loaders';
import { z } from 'astro/zod';

const posts = defineCollection({
  loader: glob({
    pattern: '**/*.{md,mdx}',
    base: './src/content/posts',
  }),
  schema: z.object({
    title: z.string(),
    date: z.coerce.date(),
    draft: z.boolean().default(false),
  }),
});

export const collections = { posts };

在 Astro 7 中,Zod 从 astro/zod 导入。内容查询则仍然使用 astro:content 中的 getCollection() 和 render()。

轻盈不是没有交互

静态优先并不意味着放弃有趣的体验。这座花园依然有主题切换、标题与标签搜索、生成式图形和交互实验。

区别在于,每一段 JavaScript 都有一个具体的理由。搜索只在打开时获取索引,图形离开视口后停止绘制,文章正文无需等待任何框架完成初始化。

性能不只是分数,也是对读者时间的一种尊重。

用适合的工具做适合的事

Astro 很适合内容驱动的项目,但它不是所有项目的答案。如果大部分界面都依赖持续变化的客户端状态,一个应用型框架可能会更直接。

重要的不是选择最流行的工具,而是先问:这个页面到底需要什么?

对一个博客来说,答案往往就是文字、链接,以及一点恰到好处的交互。

从一个关键词开始探索
↑↓ 选择 ↵ 打开在数字花园里寻找灵感