跳到主要内容
版本:3.8.1

MDX 插件

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

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

答案是:创建一个 MDX 插件!MDX 内置了插件系统,可用于自定义 Markdown 文件的解析和转换为 JSX 的方式。MDX 插件有三种典型用例:

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

如果您尝试使用 MDX playground,会注意到 MDX 转译在生成最终 JSX 输出之前,会经过两个中间步骤:Markdown AST (MDAST) 和 Hypertext AST (HAST)。MDX 插件也有两种形式:

  • Remark:处理 Markdown AST。
  • Rehype:处理 Hypertext AST。
提示

使用插件为项目中常用的 JSX 元素引入更简洁的语法。我们提供的 admonition 语法也是由 Remark 插件生成的,您可以根据自己的用例实现类似的功能。

默认插件

Docusaurus 在 Markdown 处理过程中注入了一些默认的 Remark 插件。这些插件会:

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

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

安装插件

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

npm install --save remark-math@5 rehype-katex@6
`remark-math` 和 `rehype-katex` 有什么不同?

如果您想知道 Remark 和 Rehype 有何不同,这里有一个很好的例子。`remark-math` 在 Markdown AST 上操作,它识别 `$...$` 这样的文本,然后将其转换为 JSX `...`,而不会对内容进行过多处理。这使得数学公式的提取与其渲染解耦,这意味着您只需替换 Rehype 插件,就可以将 KaTeX\KaTeX 替换为其他数学渲染器,例如 MathJax(使用 `rehype-mathjax`)。

接下来,`rehype-katex` 在 Hypertext AST 上操作,此时所有内容都已转换为类似 HTML 的标签。它遍历所有带有 `math` 类的元素,并使用 KaTeX\KaTeX 将内容解析并渲染为实际的 HTML。

警告

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

接下来,导入您的插件并通过 `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 module 插件

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.` 前缀,生成的目录仍然相同,因为生成目录的插件是在我们的自定义插件之前调用的。如果您需要在默认插件之前处理 MDAST,请使用 `beforeDefaultRemarkPlugins` 和 `beforeDefaultRehypePlugins`。

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

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