Skip to content

@astrojs/ markdoc

Astro 整合 允许使用 马克文档 创建组件、页面和内容集合条目。

¥This Astro integration enables the usage of Markdoc to create components, pages, and content collection entries.

¥Why Markdoc?

Markdoc 允许你使用 Astro 组件 增强 Markdown。如果你有在 Markdoc 中创作的现有内容,此集成允许你使用内容集合将这些文件引入你的 Astro 项目。

¥Markdoc allows you to enhance your Markdown with Astro components. If you have existing content authored in Markdoc, this integration allows you to bring those files to your Astro project using content collections.

¥Installation

Astro 包含一个 astro add 命令来自动设置官方集成。如果你愿意,你可以改用 安装集成手动

¥Astro includes an astro add command to automate the setup of official integrations. If you prefer, you can install integrations manually instead.

在新的终端窗口中运行以下命令之一。

¥Run one of the following commands in a new terminal window.

Terminal window
npx astro add markdoc

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

¥If you run into any issues, feel free to report them to us on GitHub and try the manual installation steps below.

¥Manual Install

首先,安装 @astrojs/markdoc 包:

¥First, install the @astrojs/markdoc package:

Terminal window
npm install @astrojs/markdoc

然后,使用 integrations 属性将集成应用于你的 astro.config.* 文件:

¥Then, apply the integration to your astro.config.* file using the integrations property:

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

¥VS Code Editor Integration

如果你使用 VS Code,则有一个官方 Markdoc 语言扩展,其中包括语法高亮和配置标签的自动补齐功能。请参阅 GitHub 上的语言服务器 了解更多信息。

¥If you are using VS Code, there is an official Markdoc language extension that includes syntax highlighting and autocomplete for configured tags. See the language server on GitHub for more information.

要设置扩展,请在项目根目录中创建一个 markdoc.config.json 文件,其中包含以下内容:

¥To set up the extension, create a markdoc.config.json file in the project root with following content:

markdoc.config.json
[
{
"id": "my-site",
"path": "src/content",
"schema": {
"path": "markdoc.config.mjs",
"type": "esm",
"property": "default",
"watch": true
}
}
]

使用 schema 对象将 markdoc.config.mjs 设置为配置文件,并使用 path 属性定义 Markdoc 文件的存储位置。由于 Markdoc 特定于内容集合,因此你可以使用 src/content

¥Set markdoc.config.mjs as your configuration file with the schema object, and define where your Markdoc files are stored using the path property. Since Markdoc is specific to content collections, you can use src/content.

¥Usage

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

¥Markdoc files can only be used within content collections. Add entries to any content collection using the .mdoc extension:

  • Directorysrc/
    • Directorycontent/
      • Directorydocs/
        • why-markdoc.mdoc
        • quick-start.mdoc

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

¥Then, query your collection using the Content Collection APIs:

src/pages/why-markdoc.astro
---
import { getEntryBySlug } from 'astro:content';
const entry = await getEntryBySlug('docs', 'why-markdoc');
const { Content } = await entry.render();
---
<!--Access frontmatter properties with `data`-->
<h1>{entry.data.title}</h1>
<!--Render Markdoc contents with the Content component-->
<Content />
See the Astro Content Collection docs for more information.

¥Pass Markdoc variables

你可能需要将 variables 传递给你的内容。这在传递 A/B 测试等 SSR 参数时非常有用。

¥You may need to pass variables to your content. This is useful when passing SSR parameters like A/B tests.

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

¥Variables can be passed as props via the Content component:

src/pages/why-markdoc.astro
---
import { getEntryBySlug } from 'astro:content';
const entry = await getEntryBySlug('docs', 'why-markdoc');
const { Content } = await entry.render();
---
<!--Pass the `abTest` param as a variable-->
<Content abTestGroup={Astro.params.abTestGroup} />

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

¥Now, abTestGroup is available as a variable in docs/why-markdoc.mdoc:

src/content/docs/why-markdoc.mdoc
{% if $abTestGroup === 'image-optimization-lover' %}
Let me tell you about image optimization...
{% /if %}

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

¥To make a variable global to all Markdoc files, you can use the variables attribute from your markdoc.config.mjs|ts:

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

从 Markdoc 内容访问 frontmatter

Section titled 从 Markdoc 内容访问 frontmatter

¥Access frontmatter from your Markdoc content

要访问前置内容,你可以将条目 data 属性作为变量传递,并在其中渲染内容:

¥To access frontmatter, you can pass the entry data property as a variable where you render your content:

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

现在可以在 Markdoc 中作为 $frontmatter 进行访问。

¥This can now be accessed as $frontmatter in your Markdoc.

¥Render components

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

¥@astrojs/markdoc offers configuration options to use all of Markdoc’s features and connect UI components to your content.

使用 Astro 组件作为 Markdoc 标签

Section titled 使用 Astro 组件作为 Markdoc 标签

¥Use Astro components as Markdoc tags

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

¥You can configure Markdoc tags that map to .astro components. You can add a new tag by creating a markdoc.config.mjs|ts file at the root of your project and configuring the tag attribute.

此示例渲染 Aside 组件,并允许 type 属性作为字符串传递:

¥This example renders an Aside component, and allows a type prop to be passed as a string:

markdoc.config.mjs
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 },
},
},
},
});

现在可以在带有 {% aside %} 标签的 Markdoc 文件中使用该组件。子项将被传递到组件的默认插槽:

¥This component can now be used in your Markdoc files with the {% aside %} tag. Children will be passed to your component’s default slot:

# Welcome to Markdoc 👋
{% aside type="tip" %}
Use tags like this fancy "aside" to add some _flair_ to your docs.
{% /aside %}

¥Use client-side UI components

标签和节点仅限于 .astro 文件。要将客户端 UI 组件嵌入到 Markdoc、使用渲染框架组件的封装器 .astro 组件 中,请使用你所需的 client: 指令。

¥Tags and nodes are restricted to .astro files. To embed client-side UI components in Markdoc, use a wrapper .astro component that renders a framework component with your desired client: directive.

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

¥This example wraps a React Aside.tsx component with a ClientAside.astro component:

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

现在可以将此 Astro 组件传递给配置中任何 tagnoderender 属性:

¥This Astro component can now be passed to the render prop for any tag or node in your config:

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 },
},
},
},
});

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

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

¥Use Astro components from npm packages and TypeScript files

你可能需要使用从 TypeScript 或 JavaScript 文件公开为命名导出的 Astro 组件。这在使用 npm 包和设计系统时很常见。

¥You may need to use Astro components exposed as named exports from TypeScript or JavaScript files. This is common when using npm packages and design systems.

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

¥You can pass the import name as the second argument to the component() function:

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

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

¥This generates the following import statement internally:

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

{% partial %} 标签允许你在 Markdoc 内容中渲染其他 .mdoc 文件。

¥The {% partial %} tag allows you to render other .mdoc files inside your Markdoc content.

这对于在多个文档中重复使用内容很有用,并允许你拥有不遵循你的集合架构的 .mdoc 内容文件。

¥This is useful for reusing content across multiple documents, and allows you to have .mdoc content files that do not follow your collection schema.

此示例显示了要在博客集合条目中使用的页脚的 Markdoc 部分:

¥This example shows a Markdoc partial for a footer to be used inside blog collection entries:

src/content/blog/_footer.mdoc
Social links:
- [Twitter / X](https://twitter.com/astrodotbuild)
- [Discord](https://astro.build/chat)
- [GitHub](https://github.com/withastro/astro)

使用 {% partial %} 标签在博客文章底部渲染页脚。使用相对路径或导入别名将 file 属性与文件路径一起应用:

¥Use the {% partial %} tag with to render the footer at the bottom of a blog post entry. Apply the file attribute with the path to the file, using either a relative path or an import alias:

src/content/blog/post.mdoc
# My Blog Post
{% partial file="./_footer.mdoc" %}

¥Syntax highlighting

@astrojs/markdoc 提供 志木Prisma 扩展来高亮你的代码块。

¥@astrojs/markdoc provides Shiki and Prism extensions to highlight your code blocks.

¥Shiki

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

¥Apply the shiki() extension to your Markdoc config using the extends property. You can optionally pass a shiki configuration object:

markdoc.config.mjs
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: [],
}),
],
});

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

¥Apply the prism() extension to your Markdoc config using the extends property.

markdoc.config.mjs
import { defineMarkdocConfig } from '@astrojs/markdoc/config';
import prism from '@astrojs/markdoc/prism';
export default defineMarkdocConfig({
extends: [prism()],
});
To learn about configuring Prism stylesheets, see our syntax highlighting guide.

自定义 Markdoc 节点/元素

Section titled 自定义 Markdoc 节点/元素

¥Custom Markdoc nodes / elements

你可能希望将标准 Markdown 元素(例如段落和粗体文本)渲染为 Astro 组件。为此,你可以配置 标记文档节点。如果给定节点接收属性,它们将可用作组件 props。

¥You may want to render standard Markdown elements, such as paragraphs and bolded text, as Astro components. For this, you can configure a Markdoc node. If a given node receives attributes, they will be available as component props.

此示例使用自定义 Quote.astro 组件渲染块引用:

¥This example renders blockquotes with a custom Quote.astro component:

markdoc.config.mjs
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'),
},
},
});
See the Markdoc nodes documentation to learn about all the built-in nodes and attributes.

¥Custom headings

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

¥@astrojs/markdoc automatically adds anchor links to your headings, and generates a list of headings via the content collections API. To further customize how headings are rendered, you can apply an Astro component as a Markdoc node.

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

¥This example renders a Heading.astro component using the render property:

markdoc.config.mjs
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 作为组件属性:

¥All Markdown headings will render the Heading.astro component and pass the following attributes as component props:

  • level: number 标题级别 1 - 6

  • id: string 从标题的文本内容生成的 id。这对应于 内容 render() 功能 生成的 slug

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

¥For example, the heading ### Level 3 heading! will pass level: 3 and id: 'level-3-heading' as component props.

¥Custom image components

Astro 的 <Image /> 组件不能直接在 Markdoc 中使用。但是,你可以配置 Astro 组件以在每次使用原生 ![]() 图片语法时覆盖默认图片节点,或者将其配置为自定义 Markdoc 标签以允许你指定其他图片属性。

¥Astro’s <Image /> component cannot be used directly in Markdoc. However, you can configure an Astro component to override the default image node every time the native ![]() image syntax is used, or as a custom Markdoc tag to allow you to specify additional image attributes.

覆盖 Markdoc 的默认图片节点

Section titled 覆盖 Markdoc 的默认图片节点

¥Override Markdoc’s default image node

要覆盖默认图片节点,你可以配置 .astro 组件来代替标准 <img> 进行渲染。

¥To override the default image node, you can configure an .astro component to be rendered in place of a standard <img>.

  1. Build a custom MarkdocImage.astro component to pass the required src and alt properties from your image to the <Image /> component:

    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} />
  2. The <Image /> component requires a width and height for remote images which cannot be provided using the ![]() syntax. To avoid errors when using remote images, update your component to render a standard HTML <img> tag when a remote URL src is found:

    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} />
    }
  3. Configure Markdoc to override the default image node and render 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 options
    render: component('./src/components/MarkdocImage.astro'),
    },
    },
    });
  4. The native image syntax in any .mdoc file will now use the <Image /> component to optimize your local images. Remote images may still be used, but will not be rendered by Astro’s <Image /> component.

    src/content/blog/post.mdoc
    <!-- Optimized by <Image /> -->
    ![A picture of a cat](/cat.jpg)
    <!-- Unoptimized <img> -->
    ![A picture of a dog](https://example.com/dog.jpg)

创建自定义 Markdoc 图片标签

Section titled 创建自定义 Markdoc 图片标签

¥Create a custom Markdoc image tag

Markdoc image 标签允许你在图片上设置使用 ![]() 语法无法实现的其他属性。例如,自定义图片标签允许你将 Astro 的 <Image /> 组件用于需要 widthheight 的远程图片。

¥A Markdoc image tag allows you to set additional attributes on your image that are not possible with the ![]() syntax. For example, custom image tags allow you to use Astro’s <Image /> component for remote images that require a width and height.

以下步骤将创建一个自定义 Markdoc 图片标签以显示带有标题的 <figure> 元素,并使用 Astro <Image /> 组件来优化图片。

¥The following steps will create a custom Markdoc image tag to display a <figure> element with a caption, using the Astro <Image /> component to optimize the image.

  1. Create a MarkdocFigure.astro component to receive the necessary props and render an image with a caption:

    src/components/MarkdocFigure.astro
    ---
    // src/components/MarkdocFigure.astro
    import { 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>
  2. Configure your custom image tag to render your Astro component:

    markdoc.config.mjs
    import { component, defineMarkdocConfig, nodes } from '@astrojs/markdoc/config';
    export default defineMarkdocConfig({
    tags: {
    image: {
    attributes: nodes.image.attributes,
    render: component('./src/components/MarkdocFigure.astro'),
    },
    },
    });
  3. Use the image tag in Markdoc files to display a figure with caption, providing all the necessary attributes for your component:

    {% image src="./astro-logo.png" alt="Astro Logo" width="100" height="100" caption="a caption!" %}

¥Advanced Markdoc configuration

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

¥The markdoc.config.mjs|ts file accepts all Markdoc configuration options, including tags and functions.

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

¥You can pass these options from the default export in your markdoc.config.mjs|ts file:

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 内容条目调用此函数:

¥Now, you can call this function from any Markdoc content entry:

¡Hola {% getCountryEmoji("spain") %}!
See the Markdoc documentation for more on using variables or functions in your content.

¥Set the root HTML element

Markdoc 默认使用 <article> 标签封装文档。这可以从 document Markdoc 节点更改。如果你希望删除封装器元素,则它接受 HTML 元素名称或 null

¥Markdoc wraps documents with an <article> tag by default. This can be changed from the document Markdoc node. This accepts an HTML element name or null if you prefer to remove the wrapper element:

markdoc.config.mjs
import { defineMarkdocConfig, nodes } from '@astrojs/markdoc/config';
export default defineMarkdocConfig({
nodes: {
document: {
...nodes.document, // Apply defaults for other options
render: null, // default 'article'
},
},
});

¥Integration config options

Astro Markdoc 集成可处理配置 markdoc.config.js 文件无法使用的 Markdoc 选项和功能。

¥The Astro Markdoc integration handles configuring Markdoc options and capabilities that are not available through the markdoc.config.js file.

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

¥Enables writing HTML markup alongside Markdoc tags and nodes.

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

¥By default, Markdoc will not recognize HTML markup as semantic content.

要获得更像 Markdown 的体验(其中 HTML 元素可以与你的内容一起包含),请将 allowHTML:true 设置为 markdoc 集成选项。这将启用 Markdoc 标记中的 HTML 解析。

¥To achieve a more Markdown-like experience, where HTML elements can be included alongside your content, set allowHTML:true as a markdoc integration option. This will enable HTML parsing in Markdoc markup.

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

默认情况下,任何缩进四个空格的内容都被视为代码块。不幸的是,这种行为使得很难使用任意级别的缩进来提高具有复杂结构的文档的可读性。

¥By default, any content that is indented by four spaces is treated as a code block. Unfortunately, this behavior makes it difficult to use arbitrary levels of indentation to improve the readability of documents with complex structure.

在 Markdoc 中使用嵌套标签时,缩进标签内的内容会很有帮助,以便深度级别清晰。为了支持任意缩进,我们必须禁用基于缩进的代码块,并修改其他几个考虑基于缩进的代码块的 markdown-it 解析规则。可以通过启用 ignoreIndentation 选项来应用这些更改。

¥When using nested tags in Markdoc, it can be helpful to indent the content inside of tags so that the level of depth is clear. To support arbitrary indentation, we have to disable the indent-based code blocks and modify several other markdown-it parsing rules that account for indent-based code blocks. These changes can be applied by enabling the ignoreIndentation option.

astro.config.mjs
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 %}

¥Examples

More integrations

UI Frameworks

SSR Adapters

Other integrations

Astro 中文网 - 粤ICP备13048890号