← 全部文章

Content Collections 完全指南——類型安全的內容管理

什麼是 Content Collections?

Content Collections 是 Astro 提供的一套內容管理系統,讓你用類型安全的方式組織和管理 Markdown、MDX、JSON 或 YAML 內容。

簡單來說,它解決了三個問題:

  1. 路徑約定:你的內容檔案放在哪裡、叫什麼名字
  2. 資料驗證:每篇文章的 frontmatter 是否符合預期的格式
  3. 查詢能力:如何過濾、排序和獲取內容

基本配置

src/content.config.ts 中定義一個 collection:

import { defineCollection, z } from 'astro:content';
import { glob } from 'astro/loaders';

const posts = defineCollection({
  loader: glob({ pattern: "**/*.{md,mdx}", base: "./src/content/posts" }),
  schema: z.object({
    title: z.string(),
    description: z.string(),
    date: z.coerce.date(),
    tags: z.array(z.string()).default([]),
    draft: z.boolean().default(false),
  }),
});

export const collections = { posts };

每一步的意義:

  • defineCollection — 宣告一個內容集合
  • glob loader — 告訴 Astro 哪些檔案屬於這個集合
  • z.object schema — 用 Zod 定義 frontmatter 的結構和驗證規則

Schema 進階技巧

必填與選填

Zod 讓你可以精確控制哪些字段是必需的:

schema: z.object({
  title: z.string(),                  // 必填
  description: z.string().optional(), // 選填
  date: z.coerce.date(),              // 自動轉換日期
  tags: z.array(z.string()).default([]), // 預設空陣列
  draft: z.boolean().default(false),  // 預設 false
})

自訂驗證

schema: z.object({
  rating: z.number().min(1).max(5),
  slug: z.string().regex(/^[a-z0-9-]+$/),
})

當 frontmatter 不符合 schema 時,Astro 會在構建時報錯——這比到執行期才發現問題好得多。

查詢內容

獲取所有文章

const posts = await getCollection('posts');

過濾與排序

// 只取已發布、非草稿的文章,按日期降序排列
const publishedPosts = await getCollection('posts', ({ data }) => {
  return !data.draft;
});
publishedPosts.sort((a, b) => b.data.date - a.data.date);

用 ID 查找單篇文章

// 對應 src/content/posts/my-post.md
const entry = await getEntry('posts', 'my-post');

Loader 選擇

Astro 7 引入了新的 loader 系統,目前支援三種:

Loader 用途
glob 從本地檔案系統載入 Markdown/MDX/JSON
file 載入單一 JSON/YAML 檔案作為集合
自訂 loader 從 CMS、API、資料庫載入內容

實戰範例:分類顯示文章

import { getCollection } from 'astro:content';

const allPosts = await getCollection('posts', ({ data }) => !data.draft);

// 取得所有標籤
const tags = [...new Set(allPosts.flatMap(p => p.data.tags))];

// 按標籤分組
const grouped = Object.fromEntries(
  tags.map(tag => [
    tag,
    allPosts.filter(p => p.data.tags.includes(tag))
  ])
);

小結

Content Collections 是 Astro 中最值得學習的功能之一。它讓內容管理從「隨便放檔案」變成「有結構、有驗證、可查詢」的系統。搭配 Zod schema,你可以在開發階段就 catch 掉大部分內容格式錯誤,而不是等到部署後才發現少了某個欄位。