在任何 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
来进行类型检查:
schema 在集合中强制执行一致的 frontmatter。schema
保证
当你需要引用或查询它时,你的 frontmatter 以可预测的形式存在。如果任何文件违反了它的集合 schema,Astro 将提供一个有用的错误让你知道。
schema 还使 Astro 能为内容自动生成 TypeScript 类型。为集合定义 schema 时,Astro 将自动生成并向其应用 TypeScript 接口。查询集合时,结果是完全支持 TypeScript,包括属性自动完成和类型检查。
要定义你的第一个内容 schema,如果该文件不存在的话,新建一个
src/content/config.ts
文件(
.js
和
.mjs
后缀也是支持的)。此文件应该:
从
astro:content
导入适当的工具
。
定义要验证的每个集合
。这包括一个
type
(Astro v2.5.0 中引入) 指定集合是否包含像 Markdown (
type: 'content'
) 的内容创作格式或是像 JSON 及 YAML (
type: 'data'
) 的数据格式。同样包含一个用来定义 frontmatter 形式或条目数据的
schema
。
导出一个
collections
对象
来注册你的集合。
你可以多次使用
defineCollection()
创建多个 schema。所有集合必须从这个
collections
对象中导出。
随着项目的增长,你还可以自由地重新组织代码库,并将逻辑移出
src/content/config.ts
文件。分别定义 schema 对于跨多个集合重用 schema 和与项目的其他部分共享 schema 非常有用。
你可以从任何地方导入集合 schema,包括外部 npm 包。这在使用提供了它们自己的集合 schema 的主题和库时非常有用。
Astro 使用
Zod
驱动其内容 schema。Astro 使用 Zod 能够验证集合中每个文件的 frontmatter,并在从项目内部查询内容时提供自动的 TypeScript 类型。
要在 Astro 中使用 Zod,请从
"astro:content"
中导入
z
。这是 Zod 库的重新导出,它支持 Zod 的所有特性。查看
Zod 的 README
获得关于 Zod 如何工作以及可用特性的完整文档。
集合条目也可以”引用”其他相关条目。
使用集合 API 中的
reference()
函数,可以将集合 schema 中的属性定义为另一个集合中的条目。例如,你可以要求每个
space-shuttle
条目都包含一个
pilot
属性,该属性使用
pilot
集合自己的 schema 进行类型检查、自动填充和验证。
一个常见的示例是引用以 JSON 形式存储的可重用作者个人资料或存储在同一集合中的相关帖子 URL 的博客文章:
此示例博客文章指定相关帖子的
slug
和帖子作者的
id
:
当使用
type: 'content'
时,每个内容条目从它的
文件
id
生成一个 URL 友好的
slug
属性。slug 用于直接从集合中查询条目。在根据内容创建新页面和 URL 时,它也很有用。
你可以通过将自己的
slug
属性添加到文件 frontmatter 来覆盖条目生成的 slug。这类似于其他 Web 框架的 “permalink” 特性。
"slug"
是一个特殊的保留属性名称,不允许出现在自定义集合
schema
中,也不会出现在条目的
data
属性中。
Astro 提供了两个函数来查询一个集合并返回一个(或多个)内容条目:
getCollection()
和
getEntry()
。
这两个函数都返回由
CollectionEntry
类型定义的内容条目。
首次查询集合条目后,必须再单独查询
schema 中定义的引用
。你可以再次使用
getEntry()
函数或
getEntries()
从返回的
data
对象中检索引用的条目。
getCollection()
接受一个可选的 “filter” 回调,它允许你基于条目的
id
、
slug
或
data
(frontmatter) 属性对查询进行过滤。对于
type: content
的集合,你也可以通过
slug
来过滤。
你可以使用它根据你喜欢的任何内容条件进行筛选。例如,你可以通过前端属性(如
draft
)进行过滤,以防止任何博客文章草稿发布到你的博客上:
你还可以创建草稿页面,这些页面在运行开发服务器时可用,但在生产中不会构建:
filter 参数还支持按集合中的嵌套目录进行筛选。由于
id
包含完整的嵌套路径,因此可以根据每个
id
的开头进行筛选,只返回特定嵌套目录中的项目:
查询完集合条目后,可以直接在 Astro 组件模板内访问每个条目。这使你可以呈现诸如内容链接(使用内容
slug
)或关于内容的信息(使用
data
属性)之类的 HTML。
有关将内容呈现为 HTML 的信息,请参见下面的
将内容渲染成 HTML
。
组件还可以将整个内容条目作为属性传递。
如果这样做,你可以使用
CollectionEntry
实用工具使用 TypeScript 正确地输入组件属性。此实用工具接受与集合 schema 名称匹配的字符串参数,并将继承该集合 schema 的所有属性。
一旦查询,你可以使用
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
属性(内容集合)或
id
属性(数据集合)创建你的新 URL 路径。
这将为
blog
集合中的每个条目生成一个新页面。例如,
src/content/blog/hello-world.md
上的条目将有一个
hello-world
的 slug,因此它的最终 URL 将是
post/hello-world/
。
如果你正在构建一个动态网站(使用 Astro 的 SSR 支持),则不需要在构建期间提前生成任何路径。相反,你的页面应该检查请求(使用
Astro.request
或
Astro.params
)以按需找到
slug
,然后使用
getEntry()
获取它。
如果你已经有了一个现成的 Astro 项目,比如一个博客,它使用 Markdown 或 MDX 文件在
src/pages/
内部的子文件夹中,可以考虑将相关内容或数据文件迁移到内容集合中。
请参考我们的
手把手教程
中的示例,了解如何将位于
src/pages/posts/
的基本博客示例转换为
src/content/posts
目录下的示例。该教程使用了
构建博客教程的完整项目
的代码库。
[email protected]
如果你正在处理
data
的类型集合,Astro 将为你的编辑器生成 JSON schema 文件,以获取智能提示和类型检查。这使用了一个名为
zod-to-json-schema
的库,基于你在
src/content/config.ts
中定义的集合生成项目中每个数据集合的单独文件。
此功能要求你手动将 schema 的文件路径设置为集合中每个数据条目文件的
$schema
值:
或者,你可以在编辑器设置中设置这个值。例如,要在
VSCode 的
json.schemas
设置
中设置这个值,请提供要匹配的文件路径和你的 JSON schema 的位置:
[email protected]
如果你正在处理大量的集合,你可能希望通过
experimental.contentCollectionCache
标志启用缓存的构建。这个实验性的功能优化了 Astro 的构建过程,使得未改变的集合能够在构建之间被存储和复用。
在许多情况下,这可以导致显著的构建性能提升。
虽然这个功能正在稳定中,但你也可能会遇到与存储缓存有关的问题。所以你始终可以通过运行以下命令重置你的构建缓存:
Astro 支持 remark 或者 rehype 插件
直接修改 frontmatter
。你可以通过使用从
render()
返回的
remarkPluginFrontmatter
属性在一个内容条目中访问这个修改过的 Frontmatter:
相关操作指南:
添加阅读时间
Remark 和 rehype pipeline 只在渲染内容时运行,这就解释了为什么只有在对内容条目调用
render()
之后才可以使用
remarkPluginFrontmatter
。相比之下,
getCollection()
和
getEntry()
无法直接返回这些值,因为它们不会渲染内容。
内容集合中可以使用多种日期格式,但你的集合 schema 必须匹配你在 Markdown 或 MDX YAML 中 frontmatter 所使用的格式。
YAML 使用
ISO-8601
标准来表示日期,其以
yyyy-mm-dd
格式(例如
2021-07-28
)表示并配合
z.date()
的 schema 类型来使用:
如果没有提供时区,日期格式将指定为 UTC 格式。如果你需要指定一个时区,你可以使用
ISO 8601
格式。
想要仅渲染完整 UTC 时间戳中的
YYYY-MM-DD
,可以使用 JavaScript 的
slice
方法来移除时间戳:
要查看使用
toLocaleDateString
格式化日期、月份和年份的例子,请查看官方 Astro 博客模板中的
<FormattedDate />
组件
。