@astrojs/ markdoc
此 Astro 集成 支持使用 Markdoc 创建组件、页面和内容集合条目。
为什么选择 Markdoc?
标题为“为什么选择 Markdoc?”的部分Markdoc 允许你使用 Astro 组件增强 Markdown。如果你有现有的 Markdoc 内容,此集成允许你使用内容集合将这些文件引入到 Astro 项目中。
Astro 包含一个 astro add
命令来自动设置官方集成。如果你愿意,也可以手动安装集成。
在新的终端窗口中运行以下命令之一。
npx astro add markdoc
pnpm astro add markdoc
yarn astro add markdoc
如果你遇到任何问题,请随时在 GitHub 上向我们报告,并尝试下面的手动安装步骤。
手动安装
标题为“手动安装”的部分首先,安装 @astrojs/markdoc
包
npm install @astrojs/markdoc
pnpm add @astrojs/markdoc
yarn add @astrojs/markdoc
然后,使用 integrations
属性将此集成应用到你的 astro.config.*
文件中:
import { defineConfig } from 'astro/config';import markdoc from '@astrojs/markdoc';export default defineConfig({ // ... integrations: [markdoc()],});
VS Code 编辑器集成
标题为“VS Code 编辑器集成”的部分如果你正在使用 VS Code,有一个官方的 Markdoc 语言扩展,它包含配置标签的语法高亮和自动补全功能。有关更多信息,请参阅 GitHub 上的语言服务器。
要设置此扩展,请在项目根目录中创建一个 markdoc.config.json
文件,并包含以下内容:
[ { "id": "my-site", "path": "src/content", "schema": { "path": "markdoc.config.mjs", "type": "esm", "property": "default", "watch": true } }]
将 markdoc.config.mjs
设置为你的配置文件,其中包含 schema
对象,并使用 path
属性定义 Markdoc 文件的存储位置。由于 Markdoc 专门用于内容集合,你可以使用 src/content
。
Markdoc 文件只能在内容集合中使用。使用 .mdoc
扩展名向任何内容集合添加条目。
目录src/
目录content/
目录docs/
- why-markdoc.mdoc
- quick-start.mdoc
然后,使用内容集合 API 查询你的集合。
---import { getEntry, render } from 'astro:content';
const entry = await getEntry('docs', 'why-markdoc');const { Content } = await render(entry);---
<!--Access frontmatter properties with `data`--><h1>{entry.data.title}</h1><!--Render Markdoc contents with the Content component--><Content />
传递 Markdoc 变量
标题为“传递 Markdoc 变量”的部分你可能需要向内容传递变量。这在传递 SSR 参数(如 A/B 测试)时很有用。
变量可以通过 Content
组件作为 props 传递
---import { getEntry, render } from 'astro:content';
const entry = await getEntry('docs', 'why-markdoc');const { Content } = await render(entry);---
<!--Pass the `abTest` param as a variable--><Content abTestGroup={Astro.params.abTestGroup} />
现在,abTestGroup
作为变量在 docs/why-markdoc.mdoc
中可用。
{% if $abTestGroup === 'image-optimization-lover' %}
Let me tell you about image optimization...
{% /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, render } from 'astro:content';
const entry = await getEntry('docs', 'why-markdoc');const { Content } = await render(entry);---
<Content frontmatter={entry.data} />
现在可以在 Markdoc 中以 $frontmatter
的形式访问它。
渲染组件
标题为“渲染组件”的部分@astrojs/markdoc
提供了配置选项,用于使用 Markdoc 的所有功能并将 UI 组件连接到你的内容中。
将 Astro 组件用作 Markdoc 标签
标题为“将 Astro 组件用作 Markdoc 标签”的部分你可以配置映射到 .astro
组件的 Markdoc 标签。你可以通过在项目根目录中创建一个 markdoc.config.mjs|ts
文件并配置 tag
属性来添加新标签。
此示例渲染一个 Aside
组件,并允许将 type
prop 作为字符串传递
import { defineMarkdocConfig, component } from '@astrojs/markdoc/config';
export default defineMarkdocConfig({ tags: { aside: { render: component('./src/components/Aside.astro'), attributes: { // Markdoc requires type defs for each attribute. // These should mirror the `Props` type of the component // you are rendering. // See Markdoc's documentation on defining attributes // https://markdoc.dev/docs/attributes#defining-attributes type: { type: String }, }, }, },});
现在,此组件可以在你的 Markdoc 文件中使用 {% aside %}
标签。子组件将传递到组件的默认插槽中。
# Welcome to Markdoc 👋
{% aside type="tip" %}
Use tags like this fancy "aside" to add some _flair_ to your docs.
{% /aside %}
使用客户端 UI 组件
标题为“使用客户端 UI 组件”的部分标签和节点仅限于 .astro
文件。要在 Markdoc 中嵌入客户端 UI 组件,请使用一个包装器 .astro
组件,它使用你想要的 client:
指令渲染一个框架组件。
此示例使用 ClientAside.astro
组件包装了一个 React Aside.tsx
组件
---import Aside from './Aside';---
<Aside {...Astro.props} client:load />
此 Astro 组件现在可以作为 render
prop 传递给配置中的任何标签或节点。
import { defineMarkdocConfig, component } from '@astrojs/markdoc/config';
export default defineMarkdocConfig({ tags: { aside: { render: component('./src/components/ClientAside.astro'), attributes: { type: { type: String }, }, }, },});
从 npm 包和 TypeScript 文件中使用 Astro 组件
标题为“从 npm 包和 TypeScript 文件中使用 Astro 组件”的部分你可能需要使用从 TypeScript 或 JavaScript 文件中作为命名导出公开的 Astro 组件。这在使用 npm 包和设计系统时很常见。
你可以将导入名称作为 component()
函数的第二个参数传递
import { defineMarkdocConfig, component } from '@astrojs/markdoc/config';
export default defineMarkdocConfig({ tags: { tabs: { render: component('@astrojs/starlight/components', 'Tabs'), }, },});
这会在内部生成以下导入语句
import { Tabs } from '@astrojs/starlight/components';
Markdoc 部分
标题为“Markdoc 部分”的部分Markdoc {% partial /%}
标签允许你在 Markdoc 内容中渲染其他 .mdoc
文件。
这对于在多个文档中重用内容很有用,并且允许你拥有不遵循集合模式的 .mdoc
内容文件。
对部分文件或目录使用下划线 _
前缀。这会将部分文件排除在内容集合查询之外。
此示例展示了一个 Markdoc 页脚部分,可用于博客集合条目中
Social links:
- [Twitter / X](https://twitter.com/astrodotbuild)- [Discord](https://astro.js.cn/chat)- [GitHub](https://github.com/withastro/astro)
使用 {% partial /%}
标签在博客文章底部渲染页脚。使用文件路径应用 file
属性,可以使用相对路径或导入别名。
# My Blog Post
{% partial file="./_footer.mdoc" /%}
语法高亮
标题为“语法高亮”的部分@astrojs/markdoc
提供了 Shiki 和 Prism 扩展来高亮你的代码块。
Shiki
标题为“Shiki”的部分使用 extends
属性将 shiki()
扩展应用到你的 Markdoc 配置中。你可以选择性地传递一个 Shiki 配置对象。
import { defineMarkdocConfig } from '@astrojs/markdoc/config';import shiki from '@astrojs/markdoc/shiki';
export default defineMarkdocConfig({ extends: [ shiki({ // Choose from Shiki's built-in themes (or add your own) // Default: 'github-dark' // https://shiki.style/themes theme: 'dracula', // Enable word wrap to prevent horizontal scrolling // Default: false wrap: true, // Pass custom languages // Note: Shiki has countless langs built-in, including `.astro`! // https://shiki.style/languages langs: [], }), ],});
Prism
标题为“Prism”的部分使用 extends
属性将 prism()
扩展应用到你的 Markdoc 配置中。
import { defineMarkdocConfig } from '@astrojs/markdoc/config';import prism from '@astrojs/markdoc/prism';
export default defineMarkdocConfig({ extends: [prism()],});
自定义 Markdoc 节点/元素
标题为“自定义 Markdoc 节点/元素”的部分你可能希望将标准 Markdown 元素(例如段落和粗体文本)渲染为 Astro 组件。为此,你可以配置一个 Markdoc 节点。如果给定节点接收到属性,它们将作为组件 prop 可用。
此示例使用自定义 Quote.astro
组件渲染块引用
import { defineMarkdocConfig, nodes, component } from '@astrojs/markdoc/config';
export default defineMarkdocConfig({ nodes: { blockquote: { ...nodes.blockquote, // Apply Markdoc's defaults for other options render: component('./src/components/Quote.astro'), }, },});
自定义标题
标题为“自定义标题”的部分@astrojs/markdoc
会自动为你的标题添加锚点链接,并通过内容集合 API 生成 headings
列表。为了进一步自定义标题的渲染方式,你可以将 Astro 组件应用为 Markdoc 节点。
此示例使用 render
属性渲染了一个 Heading.astro
组件
import { defineMarkdocConfig, nodes, component } from '@astrojs/markdoc/config';
export default defineMarkdocConfig({ nodes: { heading: { ...nodes.heading, // Preserve default anchor link generation render: component('./src/components/Heading.astro'), }, },});
所有 Markdown 标题都将渲染 Heading.astro
组件,并将以下 attributes
作为组件 props 传递
level: number
标题级别 1 - 6id: string
从标题文本内容生成的id
。这对应于由内容render()
函数生成的slug
。
例如,标题 ### Level 3 heading!
将传递 level: 3
和 id: 'level-3-heading'
作为组件 props。
自定义图片组件
标题为“自定义图片组件”的部分Astro 的 <Image />
组件不能直接在 Markdoc 中使用。但是,你可以配置一个 Astro 组件来覆盖默认图像节点(每次使用原生 ![]()
图像语法时),或者将其作为一个自定义 Markdoc 标签,允许你指定额外的图像属性。
覆盖 Markdoc 的默认图像节点
标题为“覆盖 Markdoc 的默认图像节点”的部分要覆盖默认图像节点,你可以配置一个 .astro
组件,以替代标准的 <img>
进行渲染。
-
构建一个自定义的
MarkdocImage.astro
组件,用于将图像的src
和alt
属性传递给<Image />
组件src/components/MarkdocImage.astro ---import { Image } from "astro:assets";interface Props {src: ImageMetadata;alt: string;}const { src, alt } = Astro.props;---<Image src={src} alt={alt} /> -
<Image />
组件要求远程图像具有width
和height
属性,而这些属性无法使用![]()
语法提供。为避免使用远程图像时出现错误,请更新组件,以便在找到远程 URLsrc
时渲染标准 HTML<img>
标签。src/components/MarkdocImage.astro ---import { Image } from "astro:assets";interface Props {src: ImageMetadata | string;alt: string;}const { src, alt } = Astro.props;---<Image src={src} alt={alt} />{typeof src === 'string' ? <img src={src} alt={alt} /> : <Image src={src} alt={alt} />} -
配置 Markdoc 以覆盖默认图像节点并渲染
MarkdocImage.astro
markdoc.config.mjs import { defineMarkdocConfig, nodes, component } from '@astrojs/markdoc/config';export default defineMarkdocConfig({nodes: {image: {...nodes.image, // Apply Markdoc's defaults for other optionsrender: component('./src/components/MarkdocImage.astro'),},},}); -
任何
.mdoc
文件中的原生图像语法现在都将使用<Image />
组件来优化你的本地图像。远程图像仍然可以使用,但不会由 Astro 的<Image />
组件渲染。src/content/blog/post.mdoc <!-- Optimized by <Image /> --><!-- Unoptimized <img> -->
创建一个自定义 Markdoc 图像标签
标题为“创建一个自定义 Markdoc 图像标签”的部分Markdoc image
标签允许你为图像设置额外的属性,这在使用 ![]()
语法时是不可能实现的。例如,自定义图像标签允许你将 Astro 的 <Image />
组件用于需要 width
和 height
的远程图像。
以下步骤将创建一个自定义 Markdoc 图像标签,用于显示带有标题的 <figure>
元素,并使用 Astro <Image />
组件优化图像。
-
创建一个
MarkdocFigure.astro
组件,以接收必要的 props 并渲染带有标题的图像src/components/MarkdocFigure.astro ---// src/components/MarkdocFigure.astroimport { Image } from "astro:assets";interface Props {src: ImageMetadata | string;alt: string;width: number;height: number;caption: string;}const { src, alt, width, height, caption } = Astro.props;---<figure><Image {src} {alt} {width} {height} />{caption && <figcaption>{caption}</figcaption>}</figure> -
配置你的自定义图像标签以渲染你的 Astro 组件
markdoc.config.mjs import { component, defineMarkdocConfig, nodes } from '@astrojs/markdoc/config';export default defineMarkdocConfig({tags: {image: {attributes: {width: {type: String,},height: {type: String,},caption: {type: String,},...nodes.image.attributes},render: component('./src/components/MarkdocFigure.astro'),},},}); -
在 Markdoc 文件中使用
image
标签显示带有标题的图片,并为你的组件提供所有必要的属性{% image src="./astro-logo.png" alt="Astro Logo" width="100" height="100" caption="a caption!" /%}
高级 Markdoc 配置
标题为“高级 Markdoc 配置”的部分markdoc.config.mjs|ts
文件接受所有 Markdoc 配置选项,包括标签和函数。
你可以从 markdoc.config.mjs|ts
文件中的默认导出传递这些选项
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") %}!
设置根 HTML 元素
标题为“设置根 HTML 元素”的部分Markdoc 默认使用 <article>
标签包装文档。这可以通过 document
Markdoc 节点进行更改。它接受 HTML 元素名称或 null
(如果你希望移除包装器元素)
import { defineMarkdocConfig, nodes } from '@astrojs/markdoc/config';
export default defineMarkdocConfig({ nodes: { document: { ...nodes.document, // Apply defaults for other options render: null, // default 'article' }, },});
集成配置选项
标题为“集成配置选项”的部分Astro Markdoc 集成处理 Markdoc 选项和功能的配置,这些选项和功能无法通过 markdoc.config.js
文件获得。
allowHTML
标题为“allowHTML”的部分启用与 Markdoc 标签和节点一起编写 HTML 标记。
默认情况下,Markdoc 不会将 HTML 标记识别为语义内容。
为了获得更像 Markdown 的体验,即 HTML 元素可以与你的内容一起包含,请将 allowHTML:true
设置为 markdoc
集成选项。这将启用 Markdoc 标记中的 HTML 解析。
import { defineConfig } from 'astro/config'; import markdoc from '@astrojs/markdoc';
export default defineConfig({ // ... integrations: [markdoc({ allowHTML: true })], });
当 allowHTML
启用时,Markdoc 文档中的 HTML 标记将渲染为实际的 HTML 元素(包括 <script>
),这使得 XSS 等攻击向量成为可能。请确保任何 HTML 标记都来自受信任的来源。
ignoreIndentation
标题为“ignoreIndentation”的部分默认情况下,任何缩进四个空格的内容都被视为代码块。不幸的是,这种行为使得难以使用任意级别的缩进来提高具有复杂结构文档的可读性。
在 Markdoc 中使用嵌套标签时,缩进标签内的内容有助于清晰地显示深度级别。为了支持任意缩进,我们必须禁用基于缩进的代码块,并修改其他几个处理基于缩进代码块的 markdown-it 解析规则。可以通过启用 ignoreIndentation 选项来应用这些更改。
import { defineConfig } from 'astro/config'; import markdoc from '@astrojs/markdoc';
export default defineConfig({ // ... integrations: [markdoc({ ignoreIndentation: true })], });
# Welcome to Markdoc with indented tags 👋
# Note: Can use either spaces or tabs for indentation
{% custom-tag %}{% custom-tag %} ### Tags can be indented for better readability
{% another-custom-tag %} This is easier to follow when there is a lot of nesting {% /another-custom-tag %}
{% /custom-tag %}{% /custom-tag %}
- Astro Markdoc 入门模板展示了如何在你的 Astro 项目中使用 Markdoc 文件。