三个周末,我给博客写了个静态生成器
2026 年 7 月 11 日 · 约 13 分钟阅读
事情是这样的:我的博客需要重建。GCP 封号之后,我决定不再依赖任何后端。但直接手写 HTML 维护几十篇文章显然不现实。我需要一个工具。
现有的选择都太重了——Hugo、Jekyll、Astro、Next.js。它们是好工具,但我不想为一个博客引入 200MB 的 node_modules。我只需要三件事:把 Markdown 转成 HTML、套一个模板、生成 RSS。
所以我在三个周末里,写了一个不到 200 行的 Node 脚本。
第一个周末:想清楚「不做什么」
大部分工具的问题不是功能太少,而是太多。我花了第一个周末列「不需要」清单:
- 不需要前端框架——纯 HTML + CSS 够用
- 不需要热更新——保存文件后手动运行一次脚本就行
- 不需要插件系统——只有一个用户,就是我
- 不需要 CMS——文件系统就是我的 CMS
- 不需要图片优化——Cloudflare 的免费 CDN 会处理
这个「减法」过程比写代码更重要。它让我想清楚一个博客到底需要什么:内容 + 排版 + 链接。其他都是噪音。
第二个周末:写代码
核心逻辑很简单:
const fs = require('fs');
const path = require('path');
const { marked } = require('marked');
// 读取所有 Markdown 文件
const posts = fs.readdirSync('content')
.filter(f => f.endsWith('.md'))
.map(f => parsePost(f))
.sort((a, b) => b.date - a.date);
// 生成每篇文章的 HTML
for (const post of posts) {
const html = applyTemplate(post);
fs.writeFileSync(`dist/${post.slug}.html`, html);
}
// 生成首页
const indexHTML = applyIndexTemplate(posts);
fs.writeFileSync('dist/index.html', indexHTML);
// 生成 RSS
const rss = generateRSS(posts);
fs.writeFileSync('dist/rss.xml', rss);
实际代码比这个多一点——处理了 frontmatter、URL 规范化、相对路径、代码高亮。但核心思路就是这三步:读取、转换、输出。
第三个周末:删掉重写
第二个周末写完之后,我试着导入了 20 篇旧文。出现了几个问题:
- 模板太死板,每篇文章的 layout 完全一样,没法做特殊排版
- 生成速度慢——虽然只有 20 篇,但每次都重新生成全部文件
- frontmatter 解析不够健壮,遇到特殊字符会崩溃
第三个周末,我把整个脚本删了,重写。这次更简单——放弃了 Markdown 自动转换,直接手写 HTML。听起来是一种倒退,但实际上:
- HTML 文件本身就是源文件,不需要「构建」步骤
- 所见即所得——写完直接刷新浏览器
- 完全控制每一行的排版
- 没有依赖,没有构建步骤,没有
node_modules
最终这个「静态生成器」退化成了一个 50 行的脚本,它做的唯一一件事就是:扫描 posts/ 目录下的 HTML 文件,提取标题和日期,生成首页的列表。
Less is actually more
这个经历让我重新思考「工具」的意义。最好的工具不是功能最多的那个,而是刚好够用的那个。对于个人博客来说,一个文本编辑器和一个 HTML 文件,就是最好的 CMS。
如果你也想写博客,我的建议是:先写,再考虑工具。先把内容写出来,放在一个 HTML 文件里,上传到任何一个能托管静态文件的地方。当你发现手动维护变得痛苦的时候,再考虑自动化。但大多数情况下,手动维护的痛苦远小于学习一个复杂框架的痛苦。
这个站的源码可以在 GitHub 上找到。没有构建步骤,clone 下来直接就能跑。