跳到主要内容

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) 和超文本 AST (HAST)。MDX 插件也有两种形式:

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

使用插件为项目中最常用的 JSX 元素引入更简短的语法。我们提供的 注释 语法也是由 Remark 插件生成的,您也可以为自己的用例做同样的事情。

默认插件

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

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

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

安装插件

MDX 插件通常是一个 npm 包,因此您可以像使用 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>,而不会对内容做太多处理。这将数学公式的提取与其渲染解耦,这意味着您可以将 KaTeX\KaTeX 与其他数学渲染器(如 MathJax(使用 rehype-mathjax ))互换,只需替换 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. 前缀。