添加于:
astro@2.0.0
在任何 Astro 项目中,内容集合是使用 Markdown 和 MDX 的最佳方式。内容集合帮助管理你的文档,校验 frontmatter,并为所有内容提供自动 TypeScript 类型安全。
一个内容集合是保留在 src/content
目录中的任何顶级目录,比如 src/content/newsletter
和 src/content/authors
。内容集合只允许在 src/content
目录中。此目录不能用于其他用处。
一个内容条目是存储在内容集合目录中的任何内容片段。内容条目存储在 Markdown (.md
)或 MDX (.mdx
)文件中。你可以使用任何想用的文件名,但是我们建议使用一致的命名方案(小写,破折号而不是空格) ,以便更容易地查找和组织内容。条目可以使用内容文件的格式,包括 Markdown (.md
) 和 MDX (.mdx
使用 MDX 集成) 或其他数据格式,包括 YAML (.yaml
) 和 JSON (.json
)。我们建议为文件使用一致的命名方案(小写、破折号而不是空格),以便更轻松地查找和组织你的内容,但这不是必须的。你还可以通过在文件名前添加下划线 (_) 来从构建中排除条目。
目录src/content/
目录newsletter/
- week-1.md
- week-2.md
- week-3.md
一旦有了一个集合,你就可以使用 Astro 的内置内容 API 开始查询集合。
Astro 将内容集合的重要元数据存储在项目中的 .astro
目录。你不需要采取任何措施来维护或更新此目录。我们希望你在项目中完全忽略它。
只要运行astro dev
,astro build
命令,.astro
目录就会自动更新。你可以随时运行astro sync
来手动更新 .astro
目录。
如果两个文件表示不同类型的内容(例如,一篇博客文章和一个作者描述文件) ,那么它们很可能属于不同的集合。这一点非常重要,因为许多特性(frontmatter 验证、自动 TypeScript 类型安全)要求集合中的所有条目共享相似的结构。
如果你发现自己正在处理不同类型的内容,则应该创建多个集合来表示每种类型。你可以在项目中创建任意多个不同的集合。
目录src/content/
目录newsletter/
目录blog/
目录authors/
- grace-hopper.json
- alan-turing.json
内容集合始终是 src/content/
目录中的顶级文件夹。不能将一个集合嵌套在另一个集合中。但是,你可以使用子目录来组织集合中的内容。
例如,可以使用以下目录结构在单个 docs
集合中组织 i18n 翻译。当查询这个集合时,将能够使用文件路径按语言过滤结果。
要充分利用内容集合,请在项目中创建一个 src/content/config.ts
文件(也支持 .js
和 .mjs
)。这是一个特殊的文件,Astro 将自动加载并使用它来配置内容集合。
如果你没有在 tsconfig.json
文件中扩展 Astro 推荐的 strict
或 strictest
的 TypeScript 设置,你可能需要更新 tsconfig.json
来启用 strictNullChecks
。
如果在 Astro 项目中使用 .js
或者 .mjs
文件,你可以启用 IntelliSense,并在编辑器中通过在 tsconfig.json
中启用 allowJs
来进行类型检查:
模式在集合中强制执行一致的frontmatter。模式保证当你需要引用或查询它时,你的 frontmatter 以可预测的形式存在。如果任何文件违反了它的集合模式,Astro 将提供一个有用的错误让你知道。
模式还支持 Astro 为内容自动输入 TypeScript。为集合定义模式时,Astro 将自动生成并向其应用 TypeScript 接口。查询集合时,结果是完全支持 TypeScript,包括属性自动完成和类型检查。
要创建你的第一个内容模式,需要创建一个 src/content/config.ts
文件,如果该文件不存在(支持.js
和.msj
)。此文件应该:
- 从
astro:content
导入适当的工具。
- 定义要用模式验证的每个集合。这包括一个
type
(Astro v2.5.0 中引入)指定集合是否包含像 Markdown (type
: ‘content’) 的内容创作格式或是像 JSON 及 YAML (type
:‘data’) 的数据格式。同样包含一个用来定义 frontmatter 形式或条目数据的 schema
。
- 导出一个
collections
对象来注册你的集合。
你可以多次使用 defeCollection()
创建多个模式。所有集合必须从单个 collections
对象内部导出。
随着项目的增长,你还可以自由地重新组织代码库,并将逻辑移出 src/content/config.ts
文件。分别定义模式对于跨多个集合重用模式和与项目的其他部分共享模式非常有用。
随着项目的增长,你还可以自由地重新组织代码库,并将逻辑移出 src/content/config.ts
文件。单独定义模式对于跨多个集合重用架构以及与项目的其他部分共享模式非常有用。
你可以从任何地方导入集合模式,包括外部 npm 包。这在处理主题和库时非常有用,这些主题和库提供自己的集合模式以供使用。
Astro 使用Zod驱动其内容模式。Astro 使用 Zod 能够验证集合中每个文件的frontmatter,并在从项目内部查询内容时提供自动的 TypeScript 类型。
要在 Astro 中使用 Zod,请从 "Astro:content"
中导入 z
。这是 Zod 库的重新导出,它支持 Zod 的所有特性。查看Zod 的 README获得关于 Zod 如何工作以及可用特性的完整文档。
集合条目也可以”引用”其他相关条目。
使用集合 API 中的 reference()
函数,可以将集合模式中的属性定义为另一个集合中的条目。 例如,你可以要求每个 space-shuttle
条目都包含一个 pilot
属性,该属性使用 pilot
集合自己的模式进行类型检查、自动填充和验证。
一个常见的示例是引用以 JSON 形式存储的可重用作者个人资料或存储在同一集合中的相关帖子 URL 的博客文章:
此示例博客文章指定相关帖子的 slug
和帖子作者的 id
:
当使用 type: 'content'
时,每个内容条目从它的file id
生成一个 URL 友好的 slug
属性。slug 用于直接从集合中查询条目。在根据内容创建新页面和 URL 时,它也很有用。
你可以通过将自己的 slug
属性添加到文件 frontmatter 来覆盖条目生成的 slug。这类似于其他 Web 框架的 “permalink” 特性。"slug"
是一个特殊的保留属性名称,不允许出现在自定义集合 schema
中,也不会出现在条目的 data
属性中。
Astro 提供了两个函数来查询一个集合并返回一个(或多个)内容条目: getCollection()
和 getEntry()
。
这两个函数都返回由CollectionEntry
类型定义的内容条目。
首次查询集合条目后,必须再单独查询模式中定义的引用。 你可以再次使用 getEntry()
函数或 getEntries()
从返回的 data
对象中检索引用的条目。
getCollection()
接受一个可选的 “filter” 回调,它允许你基于条目的 id
、slug
或 data
(frontmatter)属性对查询进行过滤。对于 type: content
的集合,你也可以通过 slug
来过滤。
你可以使用它根据您喜欢的任何内容条件进行筛选。例如,你可以通过前端属性(如 draft
)进行过滤,以防止任何博客文章草稿发布到你的博客上:
filter 参数还支持按集合中的嵌套目录进行筛选。由于 id
包含完整的嵌套路径,因此可以根据每个 id
的开头进行筛选,只返回特定嵌套目录中的项目:
查询完集合条目后,可以直接在 Astro 组件模板内访问每个条目。这使你可以呈现诸如内容链接(使用内容 slug
)或关于内容的信息(使用 data
属性)之类的 HTML。
有关将内容呈现为 HTML 的信息,请参见下面的将内容渲染成 HTML。
组件还可以将整个内容条目作为属性传递。
如果这样做,你可以使用CollectionEntry
实用工具使用 TypeScript 正确地输入组件属性。此实用工具接受与集合模式名称匹配的字符串参数,并将继承该集合模式的所有属性。
一旦查询,你可以使用render()
函数属性将集合条目渲染为 HTML。调用此函数可以访问渲染的内容和元数据,包括 <Content/>
组件和所有呈现标题的列表。
内容集合存储在 src/pages/
目录之外。这意味着默认情况下不为集合项生成路由。你将需要手动创建一个新的动态路由 ,以便从集合条目生成 HTML 页面。动态路由将映射传入的请求参数(例如: 在 src/pages/blog/[...slug].astro
中的 Astro.params.slug
)获取集合中的正确条目。
生成路由的确切方法将取决于你的构建output
模式: static
(默认值)或 server
(针对 SSR)。
如果你正在构建一个静态网站(Astro 的默认行为) ,你可以使用getStaticPaths()
函数在构建过程中从一个 src/pages/
组件创建多个页面。
调用 getStaticPaths()
中的getCollection()
来查询内容。然后,使用每个内容条目的 slug
属性创建新的 URL 路径。
这将为 blog
集合中的每个条目生成一个新页面。例如,src/content/blog/hello-world.md
上的条目将有一个 hello-world
的 slug,因此它的最终 URL 将是 post/hello-world/
。
如果你正在构建一个动态网站(使用 Astro 的 SSR 支持) ,则不需要在构建期间提前生成任何路径。相反,你的页面应该检查请求(使用 Astro.request
或 Astro.params
)以按需找到 slug
,然后使用getEntry()
获取它。
本指南展示了如何使用 src/pages/
文件夹中的 Markdown 文件将现有的 Astro 项目转换为内容集合。它使用了构建博客教程的完整项目作为例子。
-
更新到 Astro v2.0 或更高版本,并将所有集成升级到最新版本。
-
为内容集合设置 TypeScript 。
-
创建至少一个集合(src/content/
的文件夹中) ,并将 Markdown 和 MDX 页面从 src/pages/
移动到 src/content/
的这些子目录中。当同一集合中的所有文件具有相似的 frontmatter 属性时,集合的工作效果最好。因此,请选择新的文件夹结构以反映类似类型的页面。
例如,要迁移教程中的博客文章 ,请将 src/pages/post/
的内容移动到 src/content/posts/
。
-
创建一个 src/content/config.ts
文件,并为每种内容类型定义一个模式。对于博客,我们只有一种内容类型 posts
:
-
从集合中生成路由。在集合中,Markdown 和 MDX 文件不再使用 Astro 的基于文件的路由自动成为页面,因此必须自己生成页面。
对于本教程,创建一个 src/pages/post/[...slug].astro
。这个页面将使用动态路由并为每个集合条目生成一个页面。
这个页面还需要查询你的集合来获取页面 slug,并使每个路由都可以使用页面内容。
在 Markdown 或 MDX 页面的布局中渲染文章 <Content/>
。这允许你为所有的文章指定一个公共布局。
-
在个人文章的frontmatter中删除前面的 layout
定义。当渲染时,内容呈现在布局中,不再需要此属性。
-
将 Astro.glob()
替换为getCollection()
以从 Markdown 文件中获取内容和元数据。还需要更新对返回的 post 对象的引用,因为你现在可以在 data
属性上找到 frontmatter 值。
教程中的博客索引页面为每篇文章列出了一张卡片,如下所示:
教程博客项目还为每个 tag 动态生成一个页面。该页面现在变成:
同样的逻辑出现在标签索引页中,变成:
-
更新使用 layouts/MarkdownPostLayout.astro
文件中发布日期的代码。
以前,pubDate
是一个字符串。 现在,在为文章的 frontmatter 引入类型之后,pubDate
是一个 Date
。
要呈现日期,请将其转换为字符串:
最后,教程博客项目包括一个 RSS 源。这个函数还必须使用 getCollection
和 data
对象,并转换为异步函数:
有关使用内容集合的博客教程的完整示例,请参见教程 repo 的内容集合分支。
Astro 支持 remark 或者 rehype 插件直接修改 frontmatter。你可以通过使用从 render()
返回的 remarkPluginFrontmatter
属性在一个内容条目中访问这个修改过的 Frontmatter:
remark 和 rehype 管道只在渲染内容时运行,这就解释了为什么只有在对内容条目调用 render()
之后才可以使用 remarkPluginFrontmatter
。相比之下,getCollection()
和 getEntry()
不能直接返回这些值,因为它们不会渲染内容。