Astro 内容集合使用笔记
约 2 分钟阅读
内容集合(Content Collections)是 Astro 里用来管理结构化内容的机制。这次搭站把踩到的点记一下。
目录与入口配置
内容放在 src/content/<集合名>/ 下,集合本身在 src/content.config.ts 里声明。
import { defineCollection } from 'astro:content';
import { glob } from 'astro/loaders';
import { z } from 'astro/zod';
const blog = defineCollection({
loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/blog' }),
schema: z.object({
title: z.string().max(60),
pubDate: z.coerce.date(),
tags: z.array(z.string()).default([]),
draft: z.boolean().default(false),
}),
});
export const collections = { blog };
两个容易踩的细节
一是 z 的导入路径。 从 astro:content 导入 z 目前仍然可用,但已经被标记为废弃,官方建议改用 astro/zod。新项目直接按后者写,省得以后迁移。
二是 z.coerce.date() 的必要性。 frontmatter 里的日期是字符串,不做 coerce 拿到的就是字符串,getTime() 之类的调用会在运行时才报错。
查询与排序
const posts = await getCollection('blog', ({ data }) => !data.draft);
posts.sort((a, b) => b.data.pubDate.getTime() - a.data.pubDate.getTime());
过滤条件写在 getCollection 的第二个参数里,比取出来再 filter 更直观。注意排序要显式做,集合的返回顺序不保证。
草稿的处理
用 import.meta.env.PROD 区分环境,生产构建排除草稿,本地开发保留以便预览:
const posts = await getCollection('blog', ({ data }) =>
import.meta.env.PROD ? !data.draft : true
);
渲染方式的变化
新版把实例方法改成了独立函数,从 entry.render() 变成 render(entry):
import { render } from 'astro:content';
const { Content, headings } = await render(entry);
返回的 headings 可以直接用来生成文章目录,不用自己解析 Markdown。
小结
内容集合的价值主要在两个地方:一是 frontmatter 有类型校验,字段写错在构建期就能发现;二是内容与页面彻底解耦,新增文章只需要丢一个 Markdown 文件进目录。