我现在写博客的入口放在 Obsidian 里。文章本身还是 Markdown,发布交给 Astro,但每篇文章开头都需要一段固定的 frontmatter:标题、摘要、发布时间、标签、草稿状态、封面图这些信息都从这里读取。
如果每次手写,就很容易漏字段,或者日期格式不一致。所以我把新文章的默认结构做成了一个 Obsidian 模板。
模板文件放在这里:
src/content/blog/_templates/博客文章模板.md
当前模板内容很短:
---
title: "<% tp.file.title %>"
description: ""
pubDate: <% tp.date.now("YYYY-MM-DD") %>
tags: []
draft: true
cover: ""
featured: false
---
它的作用是:新建文章时先给我一个完整但还没有发布的骨架。标题默认取文件名,发布日期默认取当天,文章状态默认是草稿。这样我可以先把想法写完,再决定什么时候发布。
Templater 插件负责什么
这里用到的插件是 Obsidian 的 Templater。Obsidian 自带的 Templates 插件可以插入固定文本,但 Templater 多了一层“执行模板”的能力:它可以在插入模板时读取文件名、生成日期、按规则补全内容,还可以按文件夹自动套用指定模板。
这篇博客模板里最有用的两个动态变量是:
<% tp.file.title %>
<% tp.date.now("YYYY-MM-DD") %>
第一个变量会读取当前文件名,用来生成默认标题;第二个变量会读取当天日期,用来生成 pubDate。这样新建文章时,不需要再手动复制标题和日期。
当前 vault 里的 Templater 配置也做了自动套模板:
模板目录:_templates
自动触发:按文件夹触发
博客/ -> _templates/博客文章模板.md
前端/ -> _templates/博客文章模板.md
工作/ -> _templates/博客文章模板.md
根目录 -> _templates/博客文章模板.md
也就是说,只要在 博客、前端、工作 这些目录里新建 Markdown 文件,Templater 就会自动把 博客文章模板 插进去。_templates 目录本身被排除掉,这样编辑模板文件时不会再套一层模板。
插件怎么使用
在 Obsidian 里使用时,我通常按这个流程来:
- 打开这个博客内容目录,也就是 src/content/blog。
- 在左侧文件树里进入要发布的分类文件夹,比如 博客/。
- 新建一个 Markdown 文件,文件名先写成文章 slug,比如 2026-09-21-obsidian-post-template.md。
- Templater 会按文件夹规则自动插入 博客文章模板。
- 把自动生成的 title 改成正式中文标题。
- 补充 description、tags,如果需要封面就填写 cover。
- 正文写完后,把 draft: true 改成 draft: false。
- 回到项目根目录运行 pnpm build 检查。
如果自动模板没有触发,可以手动执行一次:打开命令面板,搜索 Templater: Insert template,选择 博客文章模板。手动插入后,Templater 仍然会把文件名和日期变量替换成当前值。
有一个小习惯比较重要:文件名最好先确定,再插入模板。因为 title 默认取文件名,如果插入后再改文件名,frontmatter 里的 title 不会自动跟着改,需要手动调整。
每个字段的含义
这几个字段里,真正决定文章能不能出现在站点上的,是 title、pubDate 和 draft。
title 是文章标题。模板里用了 Templater 的变量:
title: "<% tp.file.title %>"
新建文件时,它会自动把当前文件名填进去。比如我新建一篇 obsidian-post-template.md,标题会先变成这个文件名,后面再手动改成更适合阅读的中文标题。
description 是文章摘要。它会出现在博客列表、搜索结果、RSS 和 SEO 信息里。我通常等正文写完后再回来补这一句,因为摘要应该说清楚文章解决了什么问题,而不是只重复标题。
pubDate 是发布时间:
pubDate: <% tp.date.now("YYYY-MM-DD") %>
模板会自动写入当天日期,比如 2026-09-21。Astro 会用这个字段排序,归档页也会按它归类。
tags 是主题标签。分类已经由文件夹决定,所以 tags 只用来表达横向主题。比如这篇文章放在 博客/ 文件夹里,它的分类就是“博客”;同时它还可以有 Obsidian、Astro、Markdown 这些标签。
draft 默认是 true,这是我故意保留的安全开关。只要还是草稿,站点就不会把它列出来。真正准备发布时,把它改成:
draft: false
cover 是封面图路径。没有封面时可以留空;如果需要封面,就把图片放到 public/images/posts/,再写成:
cover: "/images/posts/example.png"
featured 用来标记是否精选。普通文章保持 false 就够了。
新建文章时怎么用
我把博客内容目录当成 Obsidian vault 使用,所以新文章直接建在分类文件夹里。
现在的规则是:一级文件夹就是博客分类。
src/content/blog/
├── 博客/
├── 前端/
└── 工作/
如果我要写一篇博客工作流相关的文章,就放到:
src/content/blog/博客/
如果是前端工程实践,就放到:
src/content/blog/前端/
模板只负责生成 frontmatter,不负责决定分类。分类由文件所在的一级文件夹决定,这样 Obsidian 里的整理方式和网站上的分类入口是同一套规则,不用在 frontmatter 里再写一遍 category。
从草稿到发布
我的发布流程基本是这样:
- 在对应分类文件夹里新建 Markdown 文件。
- 插入 博客文章模板。
- 修改标题,补充摘要和标签。
- 正文写完后,把 draft: true 改成 draft: false。
- 本地运行构建检查。
命令很简单:
pnpm build
如果构建通过,这篇文章就会进入博客列表、分类页、标签页、归档页、搜索索引、RSS、sitemap 和 llms.txt。
也就是说,发布一篇文章时真正要做的事情不多:把文件放到正确的分类文件夹,填好 frontmatter,把草稿开关关掉。
为什么默认不直接发布
模板里把 draft 设成 true,是为了避免“刚建文件就出现在网站上”。
很多文章刚开始只是一个标题,甚至只有几个关键词。如果默认发布,就会出现空文章、半成品文章,或者还没想清楚的内容被 RSS 和 sitemap 收录。
所以我更喜欢这个节奏:
- 新建时默认草稿。
- 写作时随便改。
- 发布前补齐摘要、标签和封面。
- 最后手动改成 draft: false。
这个动作虽然很小,但它给了写作一个明确的出口。只要看到 draft: false,就代表这篇文章已经准备好给别人看。
这套模板解决了什么
它没有做很复杂的事情,只是把每篇文章都需要的元信息固定下来。
对我来说,它解决的是这些小麻烦:
- 不用每次手写 frontmatter。
- 不会忘记写 draft。
- 日期格式保持一致。
- 标题可以先跟文件名同步。
- 分类直接跟 Obsidian 文件夹保持一致。
- Astro 构建时能稳定识别文章信息。
一篇文章能不能长期维护,很多时候不是靠复杂工具,而是靠这些小约定。模板让新建文章这一步变得足够轻,写作就更容易开始,也更容易发布。