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 插件也分为两种形式
使用插件为项目中最常用的 JSX 元素引入更短的语法。我们提供的 提示 语法也是由一个 Remark 插件生成的,您可以针对自己的用例执行相同的操作。
默认插件
Docusaurus 在 Markdown 处理期间注入 一些默认的 Remark 插件。这些插件将
- 生成目录;
- 为每个标题添加锚链接;
- 将图像和链接转换为
require()
调用。 - …
这些都是 Remark 插件的典型用例,如果您想实现自己的插件,它们也可以成为灵感来源。
安装插件
MDX 插件通常是 npm 包,因此您可以像使用其他 npm 包一样使用 npm 安装它们。以 数学插件 为例。
- npm
- Yarn
- pnpm
npm install --save remark-math@5 rehype-katex@6
yarn add remark-math@5 rehype-katex@6
pnpm add remark-math@5 rehype-katex@6
remark-math
和 rehype-katex
有什么区别?
如果您想知道 Remark 和 Rehype 有什么区别,这是一个很好的例子。remark-math
在 Markdown AST 上运行,它看到类似 $...$
的文本,它所做的只是将其转换为 JSX <span class="math math-inline">...</span>
,而不会对内容做太多处理。这将数学公式的提取与其渲染分离,这意味着您可以用其他数学渲染器(如 MathJax(使用 rehype-mathjax
))替换 ,只需替换 Rehype 插件即可。
接下来,rehype-katex
在超文本 AST 上运行,其中所有内容都已转换为类似 HTML 的标签。它遍历所有具有 math
类的元素,并使用 来解析并将内容渲染为实际的 HTML。
接下来,导入您的插件并通过 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.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]
语法,如下所示
import rehypeKatex from 'rehype-katex';
export default {
presets: [
[
'@docusaurus/preset-classic',
{
docs: {
rehypePlugins: [
[rehypeKatex, {strict: false}],
],
},
},
],
],
};
您应该查看插件的文档以了解其支持的选项。
创建新的 rehype/remark 插件
如果没有现有的包可以满足您的自定义需求,您可以创建自己的 MDX 插件。
例如,让我们创建一个插件,访问每个 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
中导入您的插件,并像使用已安装的插件一样使用它!
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,请使用 beforeDefaultRemarkPlugins
和 beforeDefaultRehypePlugins
。
export default {
presets: [
[
'@docusaurus/preset-classic',
{
docs: {
beforeDefaultRemarkPlugins: [sectionPrefix],
},
},
],
],
};
这将使生成的目录也包含 Section X.
前缀。