Astro 有个说法叫“默认零 JavaScript”。第一次听到会觉得是营销话术,看完它的工作方式才明白,这句话是字面意思。
传统框架的代价
用 React 写博客,哪怕页面上一个交互都没有,浏览器也要下载并解析 React 运行时。一个简单的文章页,JS 体积轻松上 200 KB。
这些 JS 做的事情,其实只是把服务端已经算好的东西,在浏览器里再算一遍。
孤岛架构
Astro 的思路是把页面看成一片静态的海洋,只把真正需要交互的部分做成“孤岛”:
---
// 这部分在构建时运行,不会进浏览器
import { getCollection } from 'astro:content';
const posts = await getCollection('posts');
---
<article>
<h1>{posts[0].data.title}</h1>
<!-- 只有这个组件会把 JS 带到浏览器 -->
<LikeButton client:load />
</article>
client:load 这类指令才告诉 Astro“这块需要 hydrate”。没写指令的组件,构建完就变成了纯 HTML。
博客里绝大多数东西——标题、正文、列表、日期——都不需要 JS。所以最终产物就是 HTML + CSS。
内容集合
Markdown 的管理用 Content Collections,schema 用 zod 校验:
import { defineCollection } from 'astro:content';
import { glob } from 'astro/loaders';
import { z } from 'astro/zod';
const posts = defineCollection({
loader: glob({ pattern: '**/*.md', base: './src/content/posts' }),
schema: z.object({
title: z.string(),
date: z.coerce.date(),
kind: z.enum(['tech', 'essay']),
tags: z.array(z.string()).default([]),
}),
});
export const collections = { posts };
写错了 frontmatter,构建时就会报错,而不是等到线上白屏。
真正需要 JS 的地方
这个站里只有三处用了 JS,加起来不到 60 行:
- 阅读进度条 —— 监听 scroll,改一个元素的宽度
- 主题切换 —— 读写 localStorage,切
data-theme - 图片灯箱 —— 点开大图,Esc 关闭
这三件事都没有必要引入框架,原生写反而更短。
需要注意的
- Shiki 明暗双主题要自己写 CSS 接住,Astro 只负责生成
--shiki-dark这些变量 - 中文字体别整套塞 webfont,用系统字体栈
- 图片放
public/下就不会被 Astro 处理;放src/assets才会走优化管线
静态站点最大的好处不是快,是省心。没有数据库要备份,没有依赖会出安全漏洞,停电了也不会丢数据。
—— 于灯下2026 年 8 月 3 日