把个人博客当作工程项目:DeskBox 的 P0–P4 复盘
从 Astro 静态站、内容校验到 SEO、搜索与多智能体协作,记录这个博客原型的工程化过程。
本文目录
这个博客本身也是一个长期维护的工程项目:deskbox-blog。它没有数据库、没有后台,内容与代码都在 Git 里;目标是让写作、构建和发布尽量可预测。
技术选择:Astro + 内容集合
站点使用 Astro 7 构建期生成静态 HTML,内容放在 src/content/blog/,由 Content Collections + Zod 校验 frontmatter。文章目录、封面和正文图片放在一起,迁移时不会出现资源路径失配。
src/content/blog/2026/10/hello-world/
├── index.md
├── cover.jpg
└── diagram.png
slug 在 frontmatter 里显式声明,构建期检查唯一性;标签不是自由字符串,而是集中注册表,未知标签会直接让构建失败。坏数据在构建期暴露,比上线后看到空白页要好。
内容管线
新增文章由 npm run new 生成目录与 frontmatter 模板:
npm run new -- "文章标题" --slug my-post --tags 前端,工程实践
草稿默认 draft: true:npm run dev 和本地预览可以看到,npm run build 会排除。发布前把 draft 改为 false,再跑完整检查。
内容规则包括:
description20–160 字;- 标签最多 3 个,必须已注册;
- 有
cover必须有coverAlt; updatedDate不能早于pubDate;slug只允许小写 ASCII 与连字符。
阅读与分发
- 文章页有粘性目录、代码复制、上一篇/下一篇和系列导航。
- 搜索使用构建后的 Pagefind 索引,只在
/search/加载。 /rss.xml输出全文,/sitemap-index.xml与robots.txt由构建生成。- 文章页输出
BlogPostingJSON-LD,首页输出WebSite+Person。 - 每篇文章构建期生成 1200×630 的 OG 图;非文章页面使用默认 OG。
性能与安全
最初移动端 LCP 超过 1.5 秒预算。后来的处理是:
- 内联首屏 CSS,去掉渲染阻塞请求;
- 内联主题初始化脚本,避免
<head>里的额外往返; - 给封面增加
widths/sizes,移动端下载更小的图。
复测结果(Slow 4G + 4× CPU):首页 LCP 从 1661ms 降到 1014ms,长文从 1812ms 降到 1291ms,CLS 保持 0。
安全方面,站点没有第三方脚本。CSP 不使用 script-src 'unsafe-inline',而是从构建产物提取内联脚本的 SHA-256 哈希;npm run check:csp 会校验哈希、策略与实际生成的 headers 配置一致。评论启用时,CSP 自动加入 giscus.app。
多智能体协作的教训
这个原型由 Claude Code、omp、agy 三条轨道并行完成,各自使用独立 worktree 和端口。回头看不复杂,但踩过的坑很具体:
- 不要假设主工作区在哪个分支。合并前先检查
git branch与git status;有他人未提交改动时,用独立 worktree 验证。 - dev 通过不等于上线通过。Pagefind、CSP headers 和缓存规则都必须在
build + preview下验证。 - 动态 DOM 的样式要放全局。Astro scoped CSS 不会作用于运行时插入的搜索结果。
- CSP 从构建产物生成,不要手写哈希;评论/分析的开关也必须进入生成器。
- 共享契约要写下来。
PostSummary、BaseLayoutprops、data-pagefind-body这些边界一旦模糊,集成阶段就会重复返工。
当前状态
- 单元测试与 E2E 覆盖内容排序、SEO、搜索、评论、导航和链接。
- 文章由示例内容与真实开源项目笔记组成。
- 评论使用 Giscus,默认点击后加载;分析默认关闭。
- 托管与域名仍未确定,生产部署不在这一阶段。
把博客当作工程项目,不意味着要写得像企业系统。它只是让每个决定都有记录、每次修改都能回滚,然后把省下来的注意力留给写作。
讨论
评论由 GitHub Discussions 提供,点击后加载。未加载前不会产生第三方请求。