静态博客生成引擎
# 案例 05 · gosite · 静态博客生成引擎(毕业设计)🎓
卷二第 5 篇 · 难度 ⭐⭐⭐⭐⭐ · 预估 16-20 小时 · 字数目标 ~2.5 万字 · 代码量 ~4000 行
# 目录介绍
# 00.案例元信息
| 项目 | 内容 |
|---|---|
| 难度 | ⭐⭐⭐⭐⭐(毕业设计) |
| 预估时长 | 16-20 小时(建议拆 4 次完成) |
| 前置章节 | 卷一全部 18 章 + 前 4 个案例 |
| 主题领域 | 工程化全家桶 + 复用前 4 个案例的产物 |
| 最终产物 | github.com/yc/gosite —— 可 go install 的真实工具 |
| 0 第三方库 | ✅(仅 stdlib + golang.org/x/...) |
功能列表:
gosite new mysite— 脚手架gosite build— 把content/*.md渲染成public/*.html,并发处理gosite serve— 本地启 HTTP + 文件监听 + 浏览器热重载(websocket)gosite deploy— git push 到 gh-pages- 主题系统:
themes/default/templates/*.html,用text/template+ 自定义函数 - 增量构建:基于文件 mtime + 内容哈希
- RSS / sitemap 自动生成
- 内置图片优化(PNG → WebP)
复用前 4 个案例:
- 用 01 gotodo 的 CLI 风格做
gosite new/build/serve/deploy - 用 02 golog 的流式处理做 markdown 解析
- 用 03 goshort 的 HTTP server 做本地预览
- 用 04 gocron 的 worker pool 做并发渲染
# 01.需求拆解
⏳ 待撰写:对标 Hugo 的精简版定位 + 必做/选做边界 + 验收标准(能 5 秒生成 1000 篇文章站点)。
# 02.架构设计
⏳ 待撰写:mermaid 全景图 + 6 次迭代分层 + 关键决策(为什么自己解析 markdown / 为什么不用 fsnotify 而用 stdlib polling)。
# 03.核心数据结构
⏳ 待撰写:
Site/Page/Theme/Builder/Watcher。
# 04.关键流程逐段实现(按 6 次迭代展示)
⏳ 待撰写,按 6 次迭代切片,约 12000 字。
# 迭代 1:脚手架(第 1 次会话)
- 1.1
gosite new命令 - 1.2
embed嵌入默认主题 - 1.3
cmd/gosite/main.go+internal/cli
串卷一第 15、17、18 章
# 迭代 2:构建(第 1 次会话)
- 2.1 极简 markdown 解析器(标题 / 段落 / 代码块 / 链接)
- 2.2 frontmatter 解析(YAML 子集)
- 2.3
text/template+ 自定义函数(date / truncate / slug) - 2.4 输出 HTML(注意
html/template转义)
串卷一第 5、7、9、10、16 章
# 迭代 3:并发渲染(第 2 次会话)
- 3.1 worker pool(复用案例 04)
- 3.2 sync.WaitGroup + errgroup 风格(自实现)
- 3.3 context 取消(Ctrl+C 立即停止所有 worker)
串卷一第 12-14 章
# 迭代 4:本地预览(第 2 次会话)
- 4.1 HTTP server(复用案例 03)
- 4.2 websocket 热重载(自实现 RFC 6455 子集)
- 4.3 文件监听(stdlib polling 方案)
串卷一第 11、13、15 章
# 迭代 5:增量构建(第 3 次会话)
- 5.1 mtime + sha256 双因子判断
- 5.2
errors.Join聚合多文件错误 - 5.3 build cache 持久化
串卷一第 8、11、16 章
# 迭代 6:CI/CD(第 4 次会话)
- 6.1 cross-compile 矩阵(5 平台 × 2 架构)
- 6.2 ldflags 注入 commit/buildtime/version
- 6.3 GitHub Actions release 工作流
- 6.4
go install github.com/yc/gosite@latest验收
串卷一第 17 章
# 05.反模式对照
⏳ 待撰写,集中讲 8-10 条工程反模式。
- ❌ 把模板当字符串拼接 → ✅
html/template自动转义- ❌ goroutine 数 = 文件数 → ✅ worker pool 限流
- ❌ 全局变量配置 → ✅ 显式传
*Config- ❌ 二进制无版本号 → ✅ ldflags 注入 commit/buildtime
- ❌ 单 Linux 二进制 → ✅ 5 平台 × 2 架构矩阵
- ❌ 错误用
log.Fatal直接 os.Exit → ✅ 返回 error 到 main,统一退出码- ❌ 不带
-race跑测试 → ✅ CI 强制go test -race- ❌
init()干活 → ✅ 显式New()构造
# 06.测试与基准
⏳ 待撰写:表驱动 + golden file 测试 + 1000 篇文章渲染 benchmark +
-race通过证据。
# 07.卷一章节反向索引(覆盖 18/18 章)
| 卷一章节 | 在本案例的落地点 |
|---|---|
| 01 简史 | §00 元信息中提到 Go 1.22 基线 |
| 02 基础语法 | 迭代 1 的 main + go.mod |
| 03 数据类型 | Page.PublishTime(time.Time) |
| 04 运算符 | 迭代 5 mtime 比较 |
| 05 复合类型 | Site.Pages []Page,frontmatter map |
| 06 流程语句 | 迭代 2 markdown 状态机的 switch |
| 07 函数 | template 自定义函数闭包 |
| 08 指针与逃逸 | 迭代 5 缓存层的接收者选择 |
| 09 结构体方法 | Page.Render() / Site.Build() |
| 10 接口与多态 | Theme 接口 + DefaultTheme 实现 |
| 11 错误处理 | 迭代 5 errors.Join 聚合 |
| 12 goroutine | 迭代 3 worker pool |
| 13 channel | 迭代 4 hot reload 广播 |
| 14 sync 包 | 迭代 5 build cache RWMutex |
| 15 IO 与文件 | 迭代 1 embed + 迭代 2 流式读 |
| 16 标准库与泛型 | 迭代 3 errgroup 自实现 |
| 17 工程化 | 迭代 6 全部 |
| 18 特性图谱 | embed / errors.Join / slog / range over func |
# 08.拓展挑战
⏳ 待撰写 5 个真正的进阶题。
- 加 i18n 多语言支持(思考
golang.org/x/text/language)- 加全文搜索(思考倒排索引 + WASM 端搜索)
- 把模板编译成 Go 代码(提前预演卷三编译原理)
- 接入 OpenGraph / Twitter Card 元数据
- 写一个自己的
gosite-theme-xxx主题包(思考 Go module 复用)
# 卷末寄语
如果你看到了这里,并且 5 个案例代码全部跑通——恭喜你,你已经完成了**从"能写 Go"到"能写 Go 项目"**的跃迁。
接下来:
- 想看 GMP / channel / GC 源码 → 卷三《底层卷》
- 想看上线后怎么调与怎么活 → 卷四《实战卷》
- 想直接干活 → 把
gositefork 一份,改成你的博客发出去
⬅ 上一篇:案例 04 · gocron 可观测的并发任务调度器
🔝 返回:卷二总导读
上次更新: 2026/06/11, 19:20:46