跳至主要内容
版本:3.5.2

MDX 插件

有时,您可能希望扩展或调整 Markdown 语法。例如

  • 如何使用图像语法(![](https://youtu.be/yKNxeF4KMsY))嵌入 YouTube 视频?
  • 如何以不同的方式设置单独一行上的链接的样式,例如作为社交卡片?
  • 如何使每个页面都以版权声明开头?

答案是:创建 MDX 插件!MDX 具有内置的 插件系统,可用于自定义如何解析 Markdown 文件并将其转换为 JSX。MDX 插件有三种典型用例

  • 使用现有的 remark 插件rehype 插件
  • 创建 remark/rehype 插件来转换现有 MDX 语法生成的元素;
  • 创建 remark/rehype 插件以向 MDX 引入新的语法。

如果您使用 MDX 游乐场,您会注意到 MDX 转译有两个中间步骤:Markdown AST (MDAST) 和超文本 AST (HAST),然后才能得到最终的 JSX 输出。MDX 插件也分为两种形式

  • Remark:处理 Markdown AST。
  • Rehype:处理超文本 AST。
提示

使用插件为项目中最常用的 JSX 元素引入更短的语法。我们提供的 提示 语法也是由一个 Remark 插件生成的,您可以针对自己的用例执行相同的操作。

默认插件

Docusaurus 在 Markdown 处理期间注入 一些默认的 Remark 插件。这些插件将

  • 生成目录;
  • 为每个标题添加锚链接;
  • 将图像和链接转换为 require() 调用。

这些都是 Remark 插件的典型用例,如果您想实现自己的插件,它们也可以成为灵感来源。

安装插件

MDX 插件通常是 npm 包,因此您可以像使用其他 npm 包一样使用 npm 安装它们。以 数学插件 为例。

npm install --save remark-math@5 rehype-katex@6
remark-mathrehype-katex 有什么区别?

如果您想知道 Remark 和 Rehype 有什么区别,这是一个很好的例子。remark-math 在 Markdown AST 上运行,它看到类似 $...$ 的文本,它所做的只是将其转换为 JSX <span class="math math-inline">...</span>,而不会对内容做太多处理。这将数学公式的提取与其渲染分离,这意味着您可以用其他数学渲染器(如 MathJax(使用 rehype-mathjax))替换 KaTeX\KaTeX,只需替换 Rehype 插件即可。

接下来,rehype-katex 在超文本 AST 上运行,其中所有内容都已转换为类似 HTML 的标签。它遍历所有具有 math 类的元素,并使用 KaTeX\KaTeX 来解析并将内容渲染为实际的 HTML。

警告

许多官方的 Remark/Rehype 插件 仅限 ES 模块,这是一种 JavaScript 模块系统,Docusaurus 支持。我们建议使用 ES 模块 配置文件,以便更容易地导入此类包。

接下来,导入您的插件并通过 docusaurus.config.js 中的插件或预设配置将其添加到插件选项中

docusaurus.config.js
import remarkMath from 'remark-math';
import rehypeKatex from 'rehype-katex';

export default {
presets: [
[
'@docusaurus/preset-classic',
{
docs: {
path: 'docs',
remarkPlugins: [remarkMath],
rehypePlugins: [rehypeKatex],
},
},
],
],
};
使用 CommonJS 配置文件?

如果您决定使用 CommonJS 配置文件,则可以借助动态导入和异步配置创建器函数来加载这些 ES 模块插件

docusaurus.config.js
module.exports = async function createConfigAsync() {
return {
presets: [
[
'@docusaurus/preset-classic',
{
docs: {
path: 'docs',
remarkPlugins: [(await import('remark-math')).default],
rehypePlugins: [(await import('rehype-katex')).default],
},
},
],
],
};
};

配置插件

某些插件可以进行配置并接受其自己的选项。在这种情况下,使用 [plugin, pluginOptions] 语法,如下所示

docusaurus.config.js
import rehypeKatex from 'rehype-katex';

export default {
presets: [
[
'@docusaurus/preset-classic',
{
docs: {
rehypePlugins: [
[rehypeKatex, {strict: false}],
],
},
},
],
],
};

您应该查看插件的文档以了解其支持的选项。

创建新的 rehype/remark 插件

如果没有现有的包可以满足您的自定义需求,您可以创建自己的 MDX 插件。

注意

以下内容并非旨在成为创建插件的完整指南,而仅仅是说明如何在 Docusaurus 中使其工作。请访问 RemarkRehype 文档以获取有关其工作原理的更深入解释。

例如,让我们创建一个插件,访问每个 h2 标题并添加 Section X. 前缀。首先,在任何位置创建插件源文件——您甚至可以将其发布为单独的 npm 包并像上面解释的那样安装它。我们将把我们的放在 src/remark/section-prefix.js 中。remark/rehype 插件只是一个接收 options 并返回在 AST 上运行的 transformer 的函数。

import {visit} from 'unist-util-visit';

const plugin = (options) => {
const transformer = async (ast) => {
let number = 1;
visit(ast, 'heading', (node) => {
if (node.depth === 2 && node.children.length > 0) {
node.children.unshift({
type: 'text',
value: `Section ${number}. `,
});
number++;
}
});
};
return transformer;
};

export default plugin;

您现在可以在 docusaurus.config.js 中导入您的插件,并像使用已安装的插件一样使用它!

docusaurus.config.js
import sectionPrefix from './src/remark/section-prefix';

export default {
presets: [
[
'@docusaurus/preset-classic',
{
docs: {
remarkPlugins: [sectionPrefix],
},
},
],
],
};
提示

transformer 有第二个参数 vfile,如果您需要访问当前 Markdown 文件的路径,它会很有用。

const plugin = (options) => {
const transformer = async (ast, vfile) => {
ast.children.unshift({
type: 'text',
value: `The current file path is ${vfile.path}`,
});
};
return transformer;
};

例如,我们的 transformImage 插件使用此参数将相对图像引用转换为 require() 调用。

注意

Docusaurus 的默认插件将在自定义 remark 插件之前运行,这意味着图像或链接已转换为带有 require() 调用的 JSX。例如,在上面的示例中,即使所有 h2 标题现在都以 Section X. 为前缀,生成的目录仍然相同,因为 TOC 生成插件在我们自定义插件之前被调用。如果您需要在默认插件执行之前处理 MDAST,请使用 beforeDefaultRemarkPluginsbeforeDefaultRehypePlugins

docusaurus.config.js
export default {
presets: [
[
'@docusaurus/preset-classic',
{
docs: {
beforeDefaultRemarkPlugins: [sectionPrefix],
},
},
],
],
};

这将使生成的目录也包含 Section X. 前缀。