跳到主要内容

旧博客迁到 Docusaurus 的内容工程:slug 兼容、归档索引和补档修复怎么做

· 阅读需 5 分钟
一介布衣
全栈开发者

最开始我也以为,把旧博客迁到 Docusaurus 主要是文件格式问题:把文章导进 blog/,补齐 frontmatter,再让站点 build 起来就差不多了。真开始做才发现,Markdown 导入只是最浅的一层。更难的是后面那几件不太显眼、却直接影响站点可信度的事:旧链接能不能继续访问,归档会不会乱,补写过的文章会不会被迁移脚本覆盖,历史内容和新内容能不能进同一套索引。

真正把这几层串起来以后,我才更愿意把这件事叫成“内容工程”。因为它处理的已经不是单篇文章,而是内容对象、历史资产和发布产物之间的关系。

旧博客迁移最难的,不是导入文件,而是保住地址和位置

如果一个站点写了很多年,旧文章就不只是老文件,它们还是外链入口、搜索索引和历史上下文。迁移时最怕的不是 build 失败,而是静悄悄地发生这些事:

  • 原来能打开的地址悄悄换了
  • 归档年份对了,月份位置却乱了
  • 旧文补写后,下一次迁移又被脚本冲掉
  • 首页和归档页看到的是两套内容视图

blogV2 里真正值钱的,不是“我把旧内容导过来了”,而是脚本、索引和展示层在尽量保住同一套内容身份。

slug 兼容最好有默认规则,不要靠人工逐篇抄旧地址

旧文章进到新系统里,第一件要稳定的就是地址。scripts/migrate-blog-posts.js 里其实已经把这层想得比较清楚了:文件名如果带日期前缀,就用 toSlug(filename) 把日期剥掉,保留后面的文章标识;如果历史 frontmatter 里已经有 original_url 或明确的 slug,则优先沿用能代表旧链接关系的字段。

这套默认规则的好处是,你不用在迁移批量旧文时一篇篇手填 slug,也不用担心后来补一批老内容时,因为文件名规则变了就把地址体系拖乱。对于技术站点来说,slug 不是视觉细节,而是内容身份。只要身份不稳,搜索收录、站内引用和外部链接都会跟着抖。

归档索引不能只是页面效果,它应该是一份正式数据

我后来很在意 src/generated/legacyArchiveData.json 这类文件,就是因为归档不该只在页面渲染时临时拼。迁移脚本里会先把文章整理成归档项,再按年份、月份和来源分组,最后写成正式数据。这样归档页、侧边导航和后续统计拿到的是同一份基础事实,而不是各自重新扫目录、各自重新算一次。

这里还有个我很喜欢的小设计:归档项会区分 source: 'v2'source: 'legacy'。这个字段看起来普通,实际非常有用。因为它让系统知道一篇文章是已经进入当前内容体系的正式内容,还是暂时仍作为历史资产存在。没有这层来源标记,后面很多补档、统计和治理动作都会混成一团。

补写修复和批量迁移,最好一开始就允许并存

内容迁移最怕的不是脚本第一次跑错,而是你花时间把某篇旧文补写好了,下一次迁移再跑一遍,又把本地修复冲掉。scripts/migrate-blog-posts.js 里我很认同的一段处理,是通过 shouldPreserveExistingTargetmergePreservedTarget 去判断:如果目标文件已经是本地人工补写过的、更完整的版本,就不要拿一份更差的迁移结果覆盖它。

这背后其实是一种很重要的迁移观:旧博客迁移不是“一次导完,从此不碰”,而是一个会和补档、修文、重写并行存在很久的过程。脚本如果只考虑批量导入,不考虑人工修复怎么保留,站点后面永远会陷在“到底该相信源站还是相信当前仓库”的冲突里。

归档、结构化数据和 sitemap 最好一起从内容对象长出来

我后来不太相信“先把页面做出来,SEO 以后再补”的说法。内容一旦开始迁移,索引产物最好同步生成。这个项目里,迁移脚本除了写归档数据,还会写开发环境下的 static/sitemap.xml;而 src/lib/blogStructuredData.js 也会明确过滤掉缺标题、缺日期、缺 permalink 的条目。

这说明站点后面的几层其实已经连在一起了:文章不是只为了单页存在,它还要进入归档、进入 sitemap、进入结构化数据、进入最近文章列表。如果内容对象在源头就没有统一字段,后面这些产物迟早会出现漂移。

为什么我更愿意把这件事叫成内容工程

把旧博客迁到 Docusaurus,表面看是在处理 Markdown,实际处理的是更长的一条链:

  • 文章在新系统里的稳定身份
  • 历史内容和当前内容的统一索引
  • 本地补写和批量迁移的冲突治理
  • 归档、结构化数据和 sitemap 的同步生成

所以我现在很少再把这件事理解成“博客搬家”。真正难的部分,不是把文本搬到新目录,而是让十几年内容在新系统里还能继续被检索、被引用、被补写,也不会因为下一轮迁移而失忆。做到这一步,迁移才不只是脚本工作,而是一套持续运行的内容工程。