内容集合
添加于:
astro@2.0.0
内容集合(Content collections) 是在任何 Astro 项目中管理内容集的最佳方式。集合有助于组织和查询文档,为你的编辑器启用智能提示和类型检查,并为所有内容提供自动的 TypeScript 类型安全。
Astro 5.0 引入了内容层(Content Layer)API,用于定义和查询内容集。这个高性能、可扩展的 API 为本地集合提供了内置的内容加载器(content loaders)。对于远程内容,你可以使用第三方和社区构建的加载器,或者创建自己的自定义加载器,从任何来源拉取数据。
项目可以继续使用 Astro v2.0 中引入的传统内容集合 API。但是,我们鼓励尽可能 更新任何现有集合。
什么是内容集合?
段落标题 什么是内容集合?你可以从结构相似的数据集中定义一个集合。这可以是一个博客文章的目录,一个产品项目的 JSON 文件,或者任何代表相同形状的多个项目的数据。
本地存储在项目中或文件系统上的集合可以包含 Markdown、MDX、Markdoc、YAML 或 JSON 文件的条目:
文件夹src/
- …
文件夹newsletter/ “newsletter” 集合
- week-1.md 一个集合条目
- week-2.md 一个集合条目
- week-3.md 一个集合条目
文件夹authors/ “author” 集合
- authors.json 包含所有集合条目的单个文件
使用对应的集合加载器,你可以从任何外部来源获取远程数据,比如 CMS、数据库或无头支付系统。
集合的 TypeScript 配置
段落标题 集合的 TypeScript 配置内容集合依靠 TypeScript 为你的编辑器提供 Zod 验证、智能提示和类型检查。如果你没有扩展 Astro 的 strict
或 strictest
TypeScript 设置,你需要确保在 tsconfig.json
中设置以下 compilerOptions
:
定义集合
段落标题 定义集合单个集合使用 defineCollection()
配置:
- 一个
loader
用于数据源(必需) - 一个
schema
用于类型安全(可选,但强烈推荐!)
集合配置文件
段落标题 集合配置文件要定义集合,你必须在项目中创建一个 src/content.config.ts
文件(也支持 .js
和 .mjs
扩展名)。这是一个特殊的文件,Astro 将根据以下结构使用它来配置你的内容集合:
定义集合 loader
段落标题 定义集合 loader内容层 API 允许你从任何地方获取你的内容(无论是本地存储在项目中还是远程存储),并使用 loader
属性来检索你的数据。
内置的加载器
段落标题 内置的加载器Astro 提供了两个内置的加载器函数(glob()
和 file()
)用于获取本地内容,也可以通过 API 来构建自己的加载器并请求远程数据。
glob()
加载器可以从文件系统的任何地方创建 Markdown、MDX、Markdoc 或 JSON 文件的目录条目。它基于 micromatch 的 glob 模式支持来接受一个匹配条目文件的 pattern
,以及你的文件所在的 base
文件路径。每个条目的 id
将从其文件名自动生成。当每个条目对应一个文件时,请使用此加载器。
file()
加载器从单个本地文件创建多个条目。文件中的每个条目必须有一个唯一的 id
键属性。它接受一个 相对你的文件的 base
文件路径,以及一个可选的 parser
函数 用于它无法自动解析的数据文件。当你的数据文件可以解析为对象数组时,请使用此加载器。
parser
函数
段落标题 parser 函数file()
加载器接受一个第二个参数,定义了一个 parser
函数。这允许你指定一个自定义解析器(例如 toml.parse
或 csv-parse
)来从文件内容创建一个集合。
file()
加载器将自动检测和解析 JSON 和 YAML 文件中的单个对象数组(基于它们的文件扩展名),无需 parser
,除非你有一个嵌套的 JSON 文件。要使用其他文件,例如 .toml
和 .csv
,你需要创建一个解析器函数。
以下示例使用 .toml
文件定义了一个内容集合 dogs
:
导入 TOML 解析器后,你可以通过将文件路径和 parser
函数传递给 file()
加载器来将 dogs
集合加载到你的项目中。类似的过程可以用来从 .csv
文件定义 cats
集合:
嵌套的 .json
文件
段落标题 嵌套的 .json 文件parser
参数还允许你从嵌套的 JSON 文档中加载单个集合。例如,这个 JSON 文件包含了多个集合:
你可以通过为每个集合传递一个自定义的 parser
来将这些集合分开:
构建一个自定义加载器
段落标题 构建一个自定义加载器你可以构建一个自定义加载器来从任何数据源(如 CMS、数据库或 API 端点)获取远程内容。
使用加载器请求数据将自动从远程数据创建一个集合。这为你提供了所有本地集合的好处,例如集合特定的 API 助手,如 getCollection()
和 render()
来查询和显示你的数据,以及模式验证。
在 Astro 集成目录 中查找社区构建和第三方加载器。
内联加载器
段落标题 内联加载器你可以在集合内部定义一个内联加载器,作为一个返回条目数组的异步函数。
这对不需要手动控制数据如何加载和存储的加载器非常有用。每当调用加载器时,它都会清除存储并重新加载所有条目。
返回的条目将存储在集合中,并可以使用 getCollection()
和 getEntry()
函数进行查询。
加载器对象
段落标题 加载器对象为了更好的控制加载过程,你可以使用内容加载器 API 来创建一个加载器对象。例如,通过直接访问 load
方法,你可以创建一个加载器,允许条目逐步更新或仅在必要时清除存储。
与创建 Astro 集成或 Vite 插件类似,你可以将你的加载器 作为 NPM 包分发,供他人在他们的项目中使用。
定义集合模式(Schema)
段落标题 定义集合模式(Schema)模式通过 Zod 验证强制执行集合中的一致的 frontmatter 或条目数据。模式 保证 了当你需要引用或查询数据时,这些数据以可预测的形式存在。如果任何文件违反了其集合模式,Astro 将提供一个有用的错误提示。
模式还为 Astro 的内容自动 TypeScript 类型提供了支持。当你为集合定义模式时,Astro 将自动生成并应用一个 TypeScript 接口。结果是当你查询集合时,完整的 TypeScript 支持,包括属性自动补全和类型检查。
集合条目的每个 frontmatter 或数据属性都必须使用 Zod 数据类型定义:
使用 Zod 定义数据类型
段落标题 使用 Zod 定义数据类型Astro 使用 Zod 来支持其内容模式。使用 Zod,Astro 能够验证集合中每个文件的数据,并在你查询内容时提供自动的 TypeScript 类型。
要在 Astro 中使用 Zod,请从 "astro:content"
导入 z
工具函数。这是 Zod 库的重新导出,支持 Zod 的所有功能。
Zod 模式方法
段落标题 Zod 模式方法所有 Zod 模式方法(例如 .parse()
、.transform()
)都可用,但有一些限制。特别是,使用 image().refine()
对图像执行自定义验证检查是不支持的。
定义集合引用
段落标题 定义集合引用集合条目还可以“引用”其他相关条目。这对于在集合模式中定义属性引用其他集合的条目非常有用。
使用集合 API 中的 reference()
函数,你可以将集合模式中的属性定义为来自另一个集合的条目。例如,你可以要求每个 space-shuttle
条目都包含一个 pilot
属性,该属性使用 pilot
集合自己的模式进行类型检查、自动补全和验证。
一个常见的例子是一个引用存储为 JSON 的可重用作者配置文件的博客文章,或者存储在同一集合中的相关文章 URL:
这个博客文章示例指定了相关文章的 id
和作者的 id
:
定义自定义 ID
段落标题 定义自定义 ID当将 Markdown、MDX、Markdoc 或 JSON 文件与 glob()
加载器一起使用时,每个内容条目的 id
将根据内容文件名自动生成一个 URL 友好的格式。id
用于直接从你的集合中查询条目。它还在从内容创建新页面和 URL 时非常有用。
你可以通过在文件的 frontmatter 或 JSON 文件的数据对象中添加自己的 slug
属性来覆盖条目生成的 id
。这类似于其他 Web 框架的 “permalink” 功能。
查询集合
段落标题 查询集合Astor 提供辅助函数来查询集合并返回一个(或多个)内容条目。
getCollection()
获取整个集合并返回一个条目数组。getEntry()
从集合中获取单个条目。
它们返回具有唯一 id
、包含所有定义属性的 data
对象,并且还将返回一个 body
,其中包含 Markdown、MDX 或 Markdoc 文档的原始、未编译的正文。
CollectionEntry
类型 返回的完整属性列表。
在 Astro 模板中使用内容
段落标题 在 Astro 模板中使用内容查询集合后,你可以直接在 Astro 组件模板中访问每个条目的内容。例如,你可以创建一个链接列表,显示条目的 frontmatter 信息,使用 data
属性。
渲染正文内容
段落标题 渲染正文内容查询后,你可以使用 render()
函数属性将 Markdown 和 MDX 条目渲染为 HTML。调用此函数将使你可以访问渲染的 HTML 内容,包括 <Content />
组件和所有已渲染标题的列表。
将内容作为 props 传递
段落标题 将内容作为 props 传递组件还可以将整个集合条目作为 prop 传递。
你可以使用 CollectionEntry
工具函数来使用 TypeScript 正确地为组件的 props 添加类型。此函数接受一个字符串参数,该参数与你的集合模式的名称匹配,并将继承该集合模式的所有属性。
过滤集合查询
段落标题 过滤集合查询getCollection()
采用一个可选的 “filter” 回调,允许你根据条目的 id
或 data
属性过滤查询。
你可以使用它来根据你喜欢的任何内容标准进行过滤。例如,你可以通过 draft
属性来过滤,以防止任何草稿博客文章发布到你的博客:
你也可以创建在运行开发服务器时可用但不在生产中构建的草稿页面。
过滤参数还支持按照集合中的嵌套目录进行过滤。由于 id
包含完整的嵌套路径,你可以通过每个 id
的开始来过滤,以仅返回特定嵌套目录中的条目:
访问引用数据
段落标题 访问引用数据首次查询集合条目后,必须单独查询 模式中定义的任何引用。你可以使用 getEntry()
函数返回单个引用项,或者使用 getEntries()
从返回的 data
对象中检索多个引用条目。
从内容生成路由
段落标题 从内容生成路由内容集合存储在 src/pages/
目录之外。这意味着默认情况下不会为集合条目生成页面或路由。
如果你想要为每个集合条目生成 HTML 页面或路由,例如单独的博客文章,你需要手动创建一个新的 动态路由。你的动态路由将把传入的请求参数(例如 Astro.params.slug
在 src/pages/blog/[...slug].astro
中)映射到每个页面的正确条目。
生成路由的确切方法取决于你的页面是预渲染的(默认)还是由服务器按需渲染的。
构建静态输出(默认)
段落标题 构建静态输出(默认)如果你正在构建一个静态网站(Astro 的默认行为),请使用 getStaticPaths()
(EN) 函数在构建期间从单个页面组件(例如 src/pages/[slug]
)创建多个页面。
在 getStaticPaths()
中调用 getCollection()
,以便在构建静态路由时为你的集合数据提供支持。然后,使用每个内容条目的 id
属性创建单独的 URL 路径。每个页面都将整个集合条目作为 prop 传递,以便在 页面模板中使用。
这将为 blog
集合中的每个条目生成一个页面路由。例如,src/blog/hello-world.md
中的条目将具有 hello-world
的 id
,因此其最终 URL 将是 /posts/hello-world/
。
如果你的自定义 slug 包含 /
字符以生成具有多个路径段的 URL,你必须在 .astro
文件名中使用 rest 参数(例如 [...slug]
) 用于这个动态路由页面。
构建服务器输出 (SSR)
段落标题 构建服务器输出 (SSR)如果你正在构建动态网站(使用 Astro 的 SSR 支持),你不需要在构建期间提前生成任何路径。相反,你的页面应该在请求时检查请求(使用 Astro.request
或 Astro.params
)以找到 slug
,然后使用 getEntry()
来按需请求它。
探索 GitHub 上博客教程演示代码的 src/pages/
文件夹 ,查看如何从你的集合创建页面,例如博客文章列表、标签页面等的完整示例!
何时创建集合
段落标题 何时创建集合只要你拥有一组共享相同结构的相关数据或内容,你就可以创建一个集合。
使用集合的大部分好处来自于:
- 定义通用数据形态,以验证单个条目是否 “正确” 或 “完整”,避免在生产中出现错误。
- 以内容为中心的 API 旨在当在页面上导入和渲染内容时,使查询变得直观(例如
getCollection()
而不是import.meta.glob()
)。 - 用于检索内容的 内容加载器 API (EN),提供了内置加载器和可用的底层 API。这里有一些第三方和社区构建的加载器可用,你可以构建自己的自定义加载器,从任何地方获取数据。
- 性能和可扩展性。内容层 API 允许数据在构建之间缓存,并适用于数万条内容条目。
在以下情况下,将 数据定义为集合:
- 你有多个文件或数据需要组织,共享相同的整体结构(例如,使用 Markdown 编写的博客文章,这些文章都具有相同的 frontmatter 属性)。
- 你有远程存储的现有内容,例如在 CMS 中,想要利用集合辅助函数和内容层 API,而不是使用
fetch()
或 SDK。 - 你需要请求(数万)个相关数据,并且需要一个能够处理大规模查询和缓存的方法。
什么时候不要使用集合
段落标题 什么时候不要使用集合当你有 多个内容需要共享相同的属性 时,集合提供了出色的结构、安全性和组织。
以下情况,集合 可能不是你的解决方案:
- 你只有一个或少量不同的页面。考虑直接使用你的内容 创建单独的页面组件,例如
src/pages/about.astro
。 - 你正在显示不由 Astro 处理的文件,例如 PDF。将这些静态资产放在项目的
public/
目录中。 - 你的数据源有自己的 SDK/客户端库用于导入,与内容加载器不兼容或不提供内容加载器,并且你更喜欢直接使用它。
- 你正在使用需要实时更新的 API。内容集合仅在构建时更新,因此如果你需要实时数据,请使用其他方法 导入文件 或 使用 按需渲染 (EN) 来 请求数据。