@astrojs/markdoc

这个 Astro 集成 允许使用 Markdoc 来创建组件、页面和内容集合条目。

Markdoc 允许你使用 Astro 组件 增强 Markdown。如果你已经使用 Markdoc 编写了现有内容,此集成允许你使用内容集合将这些文件带到 Astro 项目中。

astro add 命令行工具可以自动为你安装。在新的终端窗口中运行以下命令之一。(如果你不确定你使用的是哪个包管理器,请运行第一个命令。)然后,按照提示操作,在终端中输入 “y”(意思是 “yes”)。

终端窗口
# 使用 NPM
npx astro add markdoc
# 使用 Yarn
yarn astro add markdoc
# 使用 PNPM
pnpm astro add markdoc

如果你遇到任何问题,请随时在 GitHub 上向我们报告,并尝试下面的手动安装步骤。

首先,使用你的包管理器安装 @astrojs/markdoc 包。如果你使用的是 npm 或者不确定,请在终端中运行以下命令:

终端窗口
npm install @astrojs/markdoc

然后,在你的 astro.config.* 文件中使用 integrations 属性应用这个集成:

astro.config.mjs
import { defineConfig } from 'astro/config';
import markdoc from '@astrojs/markdoc';
export default defineConfig({
// ...
integrations: [markdoc()],
});

VS Code 默认支持 Markdown。但是,为了支持 Markdoc 编辑器,你可能希望在 VSCode 配置中添加以下设置。这样可以确保编写 Markdoc 文件时提供类似 Markdown 的编辑器体验。

.vscode/settings.json
{
"files.associations": {
"*.mdoc": "markdown"
}
}

Markdoc 文件只能在内容集合中使用。使用 .mdoc 扩展名将条目添加到任何内容集合中:

终端窗口
src/content/docs/
why-markdoc.mdoc
quick-start.mdoc

然后,使用 内容集合 API 查询你的集合:

---
import { getEntryBySlug } from 'astro:content';
const entry = await getEntryBySlug('docs', 'why-markdoc');
const { Content } = await entry.render();
---
<!--使用 `data` 访问 frontmatter 属性`-->
<h1>{entry.data.title}</h1>
<!--使用 Content 组件渲染 Markdoc 内容-->
<Content />

📚 了解更多关于 Astro 内容集合文档 的信息。

@astrojs/markdoc 提供了配置选项,以使用 Markdoc 的所有功能,并将 UI 组件连接到你的内容。

将 Astro 组件作为 Markdoc 标签

标题部分 将 Astro 组件作为 Markdoc 标签

你可以配置 Markdoc 标签,将其映射到 .astro 组件。你可以通过在项目根目录创建 markdoc.config.mjs|ts 文件并配置 tag 属性来添加新的标签。

这个例子渲染了一个 Aside 组件,并允许传递一个 type 字符串属性:

markdoc.config.mjs
import { defineMarkdocConfig, component } from '@astrojs/markdoc/config';
export default defineMarkdocConfig({
tags: {
aside: {
render: component('./src/components/Aside.astro'),
attributes: {
// Markdoc 要求每个属性都有类型定义。
// 这些应该反映你正在渲染的组件的 `Props` 类型
// 查看 Markdoc 的属性定义文档:
// https://markdoc.dev/docs/attributes#defining-attributes
type: { type: String },
},
},
},
});

现在,这个组件可以在你的 Markdoc 文件中使用 {% aside %} 标签。子元素将被传递给你的组件的默认插槽:

# 欢迎来到 Markdoc 👋
{% aside type="tip" %}
使用像这种花哨的 “aside” 标签为你的文档添加一些 _花活_
{% /aside %}

使用 npm 包和 TypeScript 文件中的 Astro 组件

标题部分 使用 npm 包和 TypeScript 文件中的 Astro 组件

你可能需要在 TypeScript 或 JavaScript 文件中使用 Astro 组件。当使用 npm 包和设计系统时,这是很常见的。

你可以将导入名称作为 component() 函数的第二个参数:

markdoc.config.mjs
import { defineMarkdocConfig, component } from '@astrojs/markdoc/config';
export default defineMarkdocConfig({
tags: {
tabs: {
render: component('@astrojs/starlight/components', 'Tabs'),
},
},
});

这将在内部生成以下导入语句:

import { Tabs } from '@astrojs/starlight/components';

@astrojs/markdoc 会自动为你的标题添加锚点链接,并且通过 内容集合 API 生成一个 headings 列表。为了进一步自定义标题的渲染方式,你可以将 Astro 组件 作为 Markdoc 节点 应用。

此示例使用 render 属性渲染 Heading.astro 组件:

markdoc.config.mjs
import { defineMarkdocConfig, nodes, component } from '@astrojs/markdoc/config';
export default defineMarkdocConfig({
nodes: {
heading: {
...nodes.heading, // 保留默认锚点链接生成
render: component('./src/components/Heading.astro'),
},
},
});

所有的 Markdown 标题都会渲染 Heading.astro 组件,并将以下 attributes 作为组件的 props 传递:

例如,标题 ### Level 3 heading! 将会传递 level: 3id: 'level-3-heading' 作为组件的 props。

@astrojs/markdoc 提供了 ShikiPrism 扩展来高亮你的代码块。

使用 extends 属性将 shiki() 扩展应用到你的 Markdoc 配置中,你可以选择传递一个 shiki 配置对象:

markdoc.config.mjs
import { defineMarkdocConfig } from '@astrojs/markdoc/config';
import shiki from '@astrojs/markdoc/shiki';
export default defineMarkdocConfig({
extends: [
shiki({
// 从 Shiki 的内置主题中进行选择(或添加你自己的主题)
// 默认:'github-dark'
// https://github.com/shikijs/shiki/blob/main/docs/themes.md
theme: 'dracula',
// 启用单词折叠以防止水平滚动
// 默认:false
wrap: true,
// 传入自定义语言
// 注意:Shiki内置了许多的 langs,包括 `.astro`!
// https://github.com/shikijs/shiki/blob/main/docs/languages.md
langs: [],
}),
],
});

使用 extends 属性将 prism() 扩展应用到你的 Markdoc 配置中。

markdoc.config.mjs
import { defineMarkdocConfig } from '@astrojs/markdoc/config';
import prism from '@astrojs/markdoc/prism';
export default defineMarkdocConfig({
extends: [prism()],
});

📚 要了解如何配置 Prism 样式表,请看我们的语法高亮指南

默认情况下,Markdoc 会使用 <article> 标签包装文档。这可以从 document Markdoc 节点中更改。这个节点接受一个 HTML 元素名称,或者如果你想删除包装元素的话,可以传递 null

markdoc.config.mjs
import { defineMarkdocConfig, nodes } from '@astrojs/markdoc/config';
export default defineMarkdocConfig({
nodes: {
document: {
...nodes.document, // 应用默认的其他配置项
render: null, // 默认 'article'
},
},
});

自定义 Markdoc 节点 / 元素

标题部分 自定义 Markdoc 节点 / 元素

你可能想要将标准的 Markdown 元素,例如段落和加粗文本,渲染为 Astro 组件。为此,你可以配置一个 Markdoc 节点。如果给定的节点接收到属性,它们可将作为组件 props 来使用。

这个例子使用一个自定义的 Quote.astro 组件渲染引用块:

markdoc.config.mjs
import { defineMarkdocConfig, nodes, component } from '@astrojs/markdoc/config';
export default defineMarkdocConfig({
nodes: {
blockquote: {
...nodes.blockquote, // 应用默认的其他配置项
render: component('./src/components/Quote.astro'),
},
},
});

📚 在他们的文档中找到 Markdoc 的所有内置节点和节点属性。

标签和节点仅限于 .astro 文件。要在 Markdoc 中嵌入客户端 UI 组件,请 使用一个包装器 .astro 组件来渲染框架组件 和你想要的 client: 指令。

此示例使用 ClientAside.astro 组件包装 React Aside.tsx 组件:

src/components/ClientAside.astro
---
import Aside from './Aside';
---
<Aside {...Astro.props} client:load />

这个 Astro 组件现在可以传递给你的配置中的任何 标签节点render 属性:

markdoc.config.mjs
import { defineMarkdocConfig, component } from '@astrojs/markdoc/config';
export default defineMarkdocConfig({
tags: {
aside: {
render: component('./src/components/ClientAside.astro'),
attributes: {
type: { type: String },
},
},
},
});

markdoc.config.mjs|ts 文件接受 所有 Markdoc 配置选项,包括 标签函数

你可以从 markdoc.config.mjs|ts 文件的默认导出中传递这些选项:

markdoc.config.mjs
import { defineMarkdocConfig } from '@astrojs/markdoc/config';
export default defineMarkdocConfig({
functions: {
getCountryEmoji: {
transform(parameters) {
const [country] = Object.values(parameters);
const countryToEmojiMap = {
japan: '🇯🇵',
spain: '🇪🇸',
france: '🇫🇷',
};
return countryToEmojiMap[country] ?? '🏳';
},
},
},
});

现在,你可以从任何 Markdoc 内容条目中调用这个函数:

¡Hola {% getCountryEmoji("spain") %}!

📚 查看 Markdoc 文档 了解更多关于在你的内容中使用变量或函数的信息。

你可能需要将 变量 传递给你的内容。当传递 SSR 参数时,这是很有用的,比如 A/B 测试。

变量可以通过 Content 组件作为 props 传递:

---
import { getEntryBySlug } from 'astro:content';
const entry = await getEntryBySlug('docs', 'why-markdoc');
const { Content } = await entry.render();
---
<!--将`abTest`参数作为变量传递-->
<Content abTestGroup={Astro.params.abTestGroup} />

现在,abTestGroup 可以作为变量在 docs/why-markdoc.mdoc 中使用:

{% if $abTestGroup === 'image-optimization-lover' %}
让我告诉你关于图像优化...
{% /if %}

要使变量对所有 Markdoc 文件全局可用,你可以使用 markdoc.config.mjs|ts 中的 variables 属性:

import { defineMarkdocConfig } from '@astrojs/markdoc/config';
export default defineMarkdocConfig({
variables: {
environment: process.env.IS_PROD ? 'prod' : 'dev',
},
});

从你的 Markdoc 内容中访问 frontmatter

标题部分 从你的 Markdoc 内容中访问 frontmatter

要访问 frontmatter,你可以在渲染内容的地方将条目 data 属性 作为变量 传递:

---
import { getEntry } from 'astro:content';
const entry = await getEntry('docs', 'why-markdoc');
const { Content } = await entry.render();
---
<Content frontmatter={entry.data} />

这样就可以在你的 Markdoc 中作为 $frontmatter 访问。

Astro Markdoc 集成处理了在 markdoc.config.js 文件中不可用的 Markdoc 选项和功能的配置。

允许在 Markdoc 标签和节点旁边编写 HTML 标记。

默认情况下,Markdoc 不会将 HTML 标记识别为语义内容。

要实现更接近 Markdown 的体验,其中 HTML 元素可以与你的内容一起使用,请将 allowHTML:true 作为 markdoc 集成选项设置。这将在 Markdoc 标记中启用 HTML 解析。

astro.config.mjs
import { defineConfig } from 'astro/config';
import markdoc from '@astrojs/markdoc';
export default defineConfig({
// ...
integrations: [markdoc({ allowHTML: true })],
});

寻求帮助,请查看 Discord 上的 #support 频道。我们友好的支持小组成员在这里帮助你!

你还可以查看我们的 Astro 集成文档 了解更多关于集成的信息。

这个项目由 Astro 核心团队维护。欢迎提交 issue 或 PR!

查看 CHANGELOG.md, 了解本集成的变更历史。

更多集成

UI 框架

SSR 适配器

其他