MDX 插件
有时,您可能希望扩展或调整 Markdown 语法。例如:
- 我如何使用图像语法嵌入 youtube 视频 (
![](https://youtu.be/yKNxeF4KMsY)
)? - 我该如何设计不同的链接,例如,作为社交卡片?
- 如何让每页都以版权声明开头?
答案是:创建一个 MDX 插件!MDX 有一个内置的插件系统,可以用来自定义如何解析 Markdown 文件并将其转换为 JSX。MDX 插件有三种典型的用例:
如果您使用MDX 游乐 场,您会注意到 MDX 编译在到达最终的 JSX 输出之前有两个中间步骤
AST (MDAST)和 Hypertext AST (HAST)。MDX 插件也有两种形式:使用插件为项目中最常用的 JSX 元素引入更短的语法。我们提供的[warning](./markdown-features- warnings .mdx)语法也是由 Remark 插件生成的,你也可以为自己的用例做同样的事情。
默认插件
Docusaurus 在 Markdown 处理过程中注入一些默认的 Remark 插件。这些插件将:
- 生成目录表;
- 为每个标题添加锚链接;
- 将图像和链接转换为
require()
调用。 - …
这些都是 Remark 插件的典型用例,如果你想实现自己的插件,它们也可以成为灵感的来源。
安装插件
MDX 插件通常是一个 npm 包,所以你可以像安装其他 npm 包一样使用 npm 来安装它们。以math plugins为例。
- 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
How are remark-math
and rehype-katex
different?
In case you are wondering how Remark and Rehype are different, here is a good example. remark-math
operates on the Markdown AST, where it sees text like $...$
, and all it does is transform that to the JSX <span class="math math-inline">...</span>
without doing too much with the content. This decouples the extraction of math formulae from their rendering, which means you can swap out with other math renderers, like MathJax (with rehype-mathjax
), just by replacing the Rehype plugin.
Next, the rehype-katex
operates on the Hypertext AST where everything has been converted to HTML-like tags already. It traverses all the elements with math
class and uses to parse and render the content to actual HTML.
许多官方的 Remark/Rehype 插件都使用了 ES Modules,这是一种新的 JavaScript 模块系统,Docusaurus 还不支持。为了解决这个问题,我们建议在 async 配置创建函数中使用动态的 import()。
接下来,通过docusaurus.config.js
中的plugin
或preset
将它们添加到插件选项中,使用动态的import()
:
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]
语法,像这样:
module.exports = async function createConfigAsync() {
return {
presets: [
[
"@docusaurus/preset-classic",
{
docs: {
rehypePlugins: [
[(await import("rehype-katex")).default, { strict: false }],
],
},
},
],
],
};
};
您应该查看插件的文档,了解它支持的选项。
创建新的 rehype/remark 插件
如果没有满足您定制需求的现有包,您可以创建自己的 MDX 插件。
例如,让我们制作一个插件,访问每个h2
标题并添加Section X.
前缀。
首先,在任何地方创建你的插件源文件——你甚至可以把它作为一个单独的 npm 包发布,然后像上面解释的那样安装它。
我们会把我们的放到src/remark/section-prefix.js
。
remark/rehype 插件只是一个接收options
并返回一个在 AST 上操作的transformer
的函数。
const visit = require("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;
};
module.exports = plugin;
现在你可以在docusaurus.config.js
中导入你的插件,并像使用已安装的插件一样使用它!
const sectionPrefix = require("./src/remark/section-prefix");
module.exports = {
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 的默认插件将在自定义注释插件之前运行,这意味着图像或链接已经通过require()
调用转换为 JSX。
例如,在上面的例子中,即使所有的h2
标题现在都以Section X.
为前缀,生成的目录仍然是一样的,因为 toc 生成插件在我们的自定义插件之前被调用。
如果你需要在默认插件之前处理 MDAST,使用beforeDefaultRemarkPlugins
和beforeDefaultRehypePlugins
。
module.exports = {
presets: [
[
"@docusaurus/preset-classic",
{
docs: {
beforeDefaultRemarkPlugins: [sectionPrefix],
},
},
],
],
};
这将使生成的目录也包含Section X.
前缀。