搜索博客与维基

技术/写作

内容集合

给 Markdown 顶部的元数据定类型规则,写错在构建时就报错。

2 分钟阅读别名:Content Collections、content collections

内容集合(Content Collections)是 Astro 提供的一层包装:把一个目录下的 Markdown 文件当成带字段的数据记录,然后用 schema 校验每条记录的字段。

为什么需要它

Markdown 文件顶部的元数据用的是 YAML,天生没有类型。pubDate 拼成 pubdate,程序不会报错,只会安静地拿不到日期。文章还在,只是排到了错误的位置,或者干脆被过滤掉。

加一层 schema 之后,同一件事变成构建失败,报出文件名和字段名。错误从「用户发现页面不对」提前到「你敲下保存的那一秒」。

三个组成部分

部分作用
loader去哪找文件,比如 glob({ base: './src/content/blog', pattern: '**/*.md' })
schema每个字段应该是什么类型,用 zod 描述
collections把上面两者导出,供页面里 getCollection() 使用

校验之外的两个好处

  1. 编辑器提示:字段有类型,敲 post.data. 会自动补全所有可用字段名。
  2. 转换一次,处处省事:用 transform 把 "a/b/c" 这种字符串统一转成数组,页面代码就不用到处判断格式。

页面里怎么用

---
import { getCollection } from 'astro:content';
const posts = await getCollection('blog');
---
{posts.map((post) => <a href={`/blog/${post.id}/`}>{post.data.title}</a>)}

post.id 是文件名(去掉扩展名),它决定了文章网址。所以改文件名等于改网址,已经发出去的链接会失效。

和其他方案的对比

  • 纯 frontmatter:没有任何校验,靠人记。
  • 外部数据库:内容在数据库里,写文章要开后台,本地的文本编辑器形同虚设。
  • 内容集合:文件是纯文本,可以进 git,同时又有类型检查。

一个反直觉的点

集合里的文件不是「页面」,是「数据」。页面是从数据渲染出来的。所以你可以从同一批数据渲染出列表页、详情页、RSS、标签页、搜索索引,各写各的。