写博客这件事,最大的敌人不是没东西写,是发布太麻烦。
我之前断断续续写过几个博客,最后都弃坑了,原因高度一致。写完一篇 Markdown,要手动搬到博客系统,要处理图片路径,要调格式,要点击发布。这套流程每多一步,坚持下去的概率就少一分。等「发布」变成一件需要专门腾出时间做的事,写作频率自然就降下来了。
这个博客系统就是为解决这个问题做的。核心理念一句话,写作和发布之间零摩擦。在 Obsidian 里写完笔记,把 frontmatter 的 publish 改成 true,剩下的全自动,几分钟后文章就上线了。这篇讲这套管线怎么搭的,以及每个选择背后的考量。
为什么写作端选 Obsidian
写作工具的选择,决定了整个工作流的体验。我选 Obsidian 有几个理由。
它是本地的。笔记存在本地文件系统,是普通的 Markdown 文件,不被任何平台锁定。这一点至关重要,因为博客系统要读这些文件来发布,本地文件意味着我可以完全掌控数据,想怎么处理就怎么处理。云端笔记工具(Notion、飞书)的数据锁在别人那里,要导出和自动化都不方便。
它支持双链和知识图谱。技术笔记之间关联很紧密,讲分布式锁要链到 CAP 定理,讲缓存要链到一致性。双链让这些关联自然建立,而且知识图谱能可视化整个笔记网络,发现自己没想到的连接。这是线性文档工具给不了的。
它的语法丰富。除了标准 Markdown,还支持 Wiki 链接 [note](/blog/note)、嵌入 > 📝 未找到笔记: note、Callout > [!type]、高亮 <mark>text</mark> 这些扩展。这些语法让笔记的表达力更强,但问题是它们不是标准 Markdown,博客系统要自己处理转换。
它有强大的插件生态。自动同步用 Git 插件,模板用 Templater,数据查询用 Dataview。这些插件把 Obsidian 从一个编辑器扩展成一个知识管理工作台。我的整个写作加发布流程,重度依赖其中几个。
发布管线的全貌
整个发布管线分五段,每段职责清晰。
写作在 Obsidian 里完成,产出的是带 Obsidian 特殊语法的 Markdown 文件。同步由 Obsidian Git 插件自动完成,每 5 分钟把 vault 里的改动 commit 加 push 到 GitHub 仓库。
构建由 GitHub Actions 触发。Actions 监听仓库的 push,一旦 vault/blog 目录有变化,就启动构建流程。构建做两件事,把 Obsidian 的特殊语法转成标准 Markdown(或者 MDX),然后用 Next.js 构建静态页面。
部署是构建的最后一步。构建产物通过 SSH 推送到服务器,替换旧的静态文件,重启服务。整个过程从写完笔记到文章上线,大概 3 到 5 分钟,全程不需要我干预。
这套管线的精髓在于,每一段都是自动的,但每一段都是可独立替换的。写作端换 Typora 也行(只要产出 Markdown),同步换其他 Git 客户端也行,构建换其他静态站点生成器也行。Obsidian 不是绑定的,只是目前最顺手的。
语法转换,最关键也最坑的一环
Obsidian 的特殊语法(Wiki 链接、Callout、嵌入、高亮)不是标准 Markdown,Next.js 的 MDX 处理器不认识。所以中间需要一个转换层,把 Obsidian 语法转成 MDX 能理解的形式。
这个转换是整个管线里工程量最大的一块。我写了一个预处理模块,用正则加字符串处理,逐个语法转换。Wiki 链接 [note](/blog/note) 转成指向 /blog/slugified-note 的普通链接。Callout > [!type] 转成带样式的 HTML 块。嵌入 > 📝 未找到笔记: note 转成对目标笔记内容的递归引用。高亮 <mark>text</mark> 转成 <mark> 标签。
这块的坑在于边界情况特别多。Wiki 链接里有别名怎么办,嵌套的 Callout 怎么处理,代码块里的 [[ 不能被当成链接。每一个都要单独处理,处理不全就会在某些笔记上崩。
PlantUML 和 Mermaid 也要特殊处理。这两种图表语法在 Obsidian 里是代码块,转换层要把它们转成对应的渲染组件(远程图片或者客户端渲染)。这块踩过不少坑,比如 PlantUML 的编码、Mermaid 的客户端渲染失败兜底。
转换层要宽容,遇到不认识的语法不要崩,原样保留就好。笔记的内容是用户产的,各种奇怪的写法都会出现,转换层崩了等于整篇笔记都发不出去。我的做法是,每个语法转换都包在 try-catch 里,转不了的保留原文,至少让能转的部分正常显示。构建失败比渲染瑕疵严重得多。
发布控制,一个字段搞定
哪些笔记发布、哪些不发布,控制方式要简单。我用 frontmatter 里的 publish 字段。publish: true 就发布,不写或者 false 就不发布。
这个设计的好处是,控制粒度精确到单篇笔记,而且就在笔记自己的 frontmatter 里,不用额外维护一个发布清单。写完想发就加 publish: true,不想发就不加,想下线就改回 false。
还有一些自动规则。某些目录(比如草稿、私人笔记)默认不发布,除非显式标记。笔记内容太短(少于一定字数)也不发布,避免把半成品发出去。这些规则在构建时的过滤逻辑里实现。
一些踩过的坑
图片路径是个经典坑。Obsidian 里图片引用用的是相对路径或者 vault 内路径,但博客上线后图片要在 public 目录下。我的处理是,构建时把 vault 里的图片资源拷到 public 目录,同时把笔记里的图片路径重写成上线后的路径。这块要处理好同名冲突和路径映射。
Frontmatter 的字段也要对齐。Obsidian 笔记的 frontmatter 字段(title、date、tags、description)要和博客系统期望的对上。日期格式要能被解析,slug 为空时从文件名生成。这些边界处理好,写作端就不用关心博客系统的细节,只管按 Obsidian 的习惯写。
增量构建。笔记多了之后全量构建会慢,理想是只构建变化的笔记。这块用 Next.js 的增量静态再生或者构建缓存来实现,能大幅缩短构建时间。目前我的笔记量还没到需要优化的程度,但这是未来的一个改进点。
这套工作流带给我的
用了这套管线之后,最直接的变化是写作频率上来了。因为发布不再是阻力,写完就发,发完就在线上,这个正反馈让人更愿意写。
更深的变化是,博客和笔记统一了。以前笔记是笔记、博客是博客,两边维护很累。现在笔记就是博客的源,写笔记等于在写博客,只是哪些发哪些不发的一个字段差别。知识沉淀和分享成了一个连续的过程,不是两件事。
这套「无感发布」的工作流,核心不是某个技术多炫,是把写作到发布之间的每一步摩擦都尽量消除。工具和自动化是手段,目的是让你能坚持产出。能坚持产出,这套系统就值了。技术人最大的浪费,是脑子里想了很多、手上记了一些,但因为发布麻烦最后没沉淀下来。这套管线就是为了让沉淀这件事变得毫不费力。






