为什么这个博客可以一行 JavaScript 都不要
搭这个博客之前我列了一张清单,问自己:访问者打开一篇文章,到底需要浏览器做什么?
答案是什么都不用做。他需要的是文字、排版、一张图片。这些东西在服务器上是死的,传过去就能看。
运行时复杂度与构建时复杂度
前端框架的流行让人产生一种错觉:复杂度是免费的。其实不是,它只是被推迟了——从构建时推迟到了运行时,从你的机器推迟到了每一个访客的手机上。
同一份复杂度,放在两边代价完全不同:
| 构建时 | 运行时 | |
|---|---|---|
| 谁来承担 | 你的电脑,一次 | 每个访客,每次 |
| 出错的后果 | 构建失败,你立刻知道 | 白屏,访客直接走 |
| 能否回滚 | 改一行重跑 | 改一行,等下次访问 |
一篇文章的渲染逻辑,一年可能只变两次;但它每次被访问都要重新执行一遍。把不变的活放在构建时做,是稳赚的。
内容就是文件
这个站里的每一篇文章,都是一个 Markdown 文件:
content/notes/2026-09-18-tui-shitou-de-na-ge-zao-chen.md
文件开头有一段被称为 front-matter 的说明:
---
title: 推石头的那个早晨
date: 2026-09-18
tags: [加缪, 读书笔记]
---
构建的时候,Astro 会扫描整个目录,用一份 schema 校验每个文件的字段,然后把它们变成路由和列表页:
const postCollection = (dir) =>
defineCollection({
loader: glob({ base: `./content/${dir}`, pattern: '**/*.md' }),
schema: z.object({
title: z.string(),
date: z.coerce.date(),
tags: z.array(z.string()).default([]),
}),
});
好处是:字段名写错,构建直接失败,而不是等到页面上少显示一个日期你才发现。
代价是什么
天下没有白拿的东西。零 JavaScript 换来的代价是:
- 没有客户端路由,每次点击都是整页跳转。但静态 HTML 加 HTTP 缓存之后,这个跳转通常比 SPA 的首次渲染更快。
- 没法做需要登录的交互。留言板因此必须外挂一个独立的后端,不能和页面打包在一起。
- 搜索要额外处理。我用构建期生成索引的 Pagefind,仍然是纯前端查询,不需要服务器。
一个判断标准
我现在的判断标准很粗暴:这个功能,如果访客关掉 JavaScript 会怎样?
导航、阅读、切换深浅色、看代码——全都应该照常。留言板除外,它是唯一一个真的需要脚本的功能,而且它挂了也不影响读文章。
一个博客最核心的能力是让人把字读完。其他都是附加项。