把个人博客当作工程项目: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,再跑完整检查。

内容规则包括:

  • description 20–160 字;
  • 标签最多 3 个,必须已注册;
  • 有 cover 必须有 coverAlt;
  • updatedDate 不能早于 pubDate;
  • slug 只允许小写 ASCII 与连字符。

阅读与分发

  • 文章页有粘性目录、代码复制、上一篇/下一篇和系列导航。
  • 搜索使用构建后的 Pagefind 索引,只在 /search/ 加载。
  • /rss.xml 输出全文,/sitemap-index.xml 与 robots.txt 由构建生成。
  • 文章页输出 BlogPosting JSON-LD,首页输出 WebSite + Person。
  • 每篇文章构建期生成 1200×630 的 OG 图;非文章页面使用默认 OG。

性能与安全

最初移动端 LCP 超过 1.5 秒预算。后来的处理是:

  1. 内联首屏 CSS,去掉渲染阻塞请求;
  2. 内联主题初始化脚本,避免 <head> 里的额外往返;
  3. 给封面增加 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、BaseLayout props、data-pagefind-body 这些边界一旦模糊,集成阶段就会重复返工。

当前状态

  • 单元测试与 E2E 覆盖内容排序、SEO、搜索、评论、导航和链接。
  • 文章由示例内容与真实开源项目笔记组成。
  • 评论使用 Giscus,默认点击后加载;分析默认关闭。
  • 托管与域名仍未确定,生产部署不在这一阶段。

把博客当作工程项目,不意味着要写得像企业系统。它只是让每个决定都有记录、每次修改都能回滚,然后把省下来的注意力留给写作。

讨论

评论由 GitHub Discussions 提供,点击后加载。未加载前不会产生第三方请求。