FisherHub Blog
← 返回列表 | 开发实践

Astro Content Collections 深度解析:从 Schema 到 Loader

带你彻底搞懂 Astro 的内容管理系统——glob loader、frontmatter 校验、类型生成和 render API

Content Collections 是什么

Astro 的内容集合(Content Collections)是一套类型安全的内容管理方案。它允许你:

  1. 定义内容的 Schema(Zod)
  2. 自动生成 TypeScript 类型
  3. getCollection() API 查询内容
  4. 渲染 MDX/Markdown 为 HTML

Schema 定义

// src/content.config.ts
import { defineCollection, z } from 'astro:content';
import { glob } from 'astro/loaders';

const blog = defineCollection({
  loader: glob({
    pattern: '**/*.mdx',
    base: './src/content/blog',
  }),
  schema: z.object({
    title: z.string(),
    description: z.string(),
    pubDate: z.coerce.date(),
    updatedDate: z.coerce.date().optional(),
    category: z.string().default('未分类'),
    tags: z.array(z.string()).default([]),
    draft: z.boolean().default(false),
    heroImage: z.string().optional(),
  }),
});

export const collections = { blog };

查询内容

// 全部文章
const posts = await getCollection('blog');

// 过滤非草稿
const published = await getCollection('blog', ({ data }) => !data.draft);

// 按日期排序
const sorted = published.sort(
  (a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf()
);

渲染内容

---
import { render } from 'astro:content';

const { post } = Astro.props;
const { Content } = await render(post);
---
<article>
  <Content />
</article>

Glob Loader 最佳实践

  • pattern 支持 glob 表达式,**/*.mdx 匹配所有子目录
  • base 是内容根目录的绝对/相对路径
  • 可以创建多个 collection,如 blognotesdocs

常见问题

Q: draft 过滤为什么是 !data.draft 而不是 data.draft === false

因为 Starlight 等框架用 data.draft === false 判断,确保显式设置才生效。但自己用 !data.draft 更简洁——没有 draft 字段的旧文章不会被过滤。

内容集合是 Astro 最核心的特性之一,花时间理解它的设计,会发现它比你想象的更强大。