MDX 插件
¥MDX Plugins
有时,你可能想要扩展或调整 Markdown 语法。例如:
¥Sometimes, you may want to extend or tweak your Markdown syntax. For example:
-
如何使用图片语法 (
![](https://youtu.be/yKNxeF4KMsY)
) 嵌入 YouTube 视频?¥How do I embed youtube videos using the image syntax (
![](https://youtu.be/yKNxeF4KMsY)
)? -
如何以不同的方式设置独立行的链接样式,例如作为社交卡?
¥How do I style links that are on their own lines differently, e.g., as a social card?
-
如何使每个页面都以版权声明开头?
¥How do I make every page start with a copyright notice?
答案是:创建一个 MDX 插件!MDX 有一个内置的 插件系统,可用于自定义如何解析 Markdown 文件并将其转换为 JSX。MDX 插件有三种典型用例:
¥And the answer is: create an MDX plugin! MDX has a built-in plugin system that can be used to customize how the Markdown files will be parsed and transformed to JSX. There are three typical use-cases of MDX plugins:
-
¥Using existing remark plugins or rehype plugins;
-
创建 remark/rehype 插件来转换现有 MDX 语法生成的元素;
¥Creating remark/rehype plugins to transform the elements generated by existing MDX syntax;
-
创建 remark/rehype 插件以向 MDX 引入新语法。
¥Creating remark/rehype plugins to introduce new syntaxes to MDX.
如果你使用 MDX 在线运行,你会注意到 MDX 转译有两个中间步骤:在到达最终 JSX 输出之前,Markdown AST (MDAST) 和超文本 AST (HAST)。MDX 插件也有两种形式:
¥If you play with the MDX playground, you would notice that the MDX transpilation has two intermediate steps: Markdown AST (MDAST), and Hypertext AST (HAST), before arriving at the final JSX output. MDX plugins also come in two forms:
-
Remark:处理 Markdown AST。
¥Remark: processes the Markdown AST.
-
Rehype:处理超文本 AST。
¥Rehype: processes the Hypertext AST.
使用插件为项目中最常用的 JSX 元素引入更短的语法。我们提供的 admonition 语法也是由 Remark 插件生成的,你可以针对自己的用例执行相同的操作。
¥Use plugins to introduce shorter syntax for the most commonly used JSX elements in your project. The admonition syntax that we offer is also generated by a Remark plugin, and you could do the same for your own use case.
默认插件
¥Default plugins
Docusaurus 在 Markdown 处理期间注入 一些默认的 Remark 插件。这些插件将:
¥Docusaurus injects some default Remark plugins during Markdown processing. These plugins would:
-
生成目录;
¥Generate the table of contents;
-
为每个标题添加锚链接;
¥Add anchor links to each heading;
-
将图片和链接转换为
require()
调用。¥Transform images and links to
require()
calls. -
…
这些都是 Remark 插件的典型用例,如果你想实现自己的插件,它们也可以成为灵感的来源。
¥These are all typical use-cases of Remark plugins, which can also be a source of inspiration if you want to implement your own plugin.
安装插件
¥Installing plugins
MDX 插件通常是一个 npm 软件包,因此你可以像使用 npm 来安装其他 npm 软件包一样安装它们。以 数学插件 为例。
¥An MDX plugin is usually an npm package, so you install them like other npm packages using npm. Take the math plugins as an example.
- 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?
如果你想知道 Remark 和 Rehype 有何不同,这里有一个很好的例子。remark-math
在 Markdown AST 上运行,它看到像 $...$
这样的文本,它所做的只是将其转换为 JSX <span class="math math-inline">...</span>
,而不对内容做太多处理。这将数学公式的提取与渲染分离,这意味着你可以将 与其他数学渲染器交换,例如 MathJax(带有 rehype-mathjax
),只需替换 Rehype 插件即可。
¥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.
接下来,rehype-katex
在超文本 AST 上运行,其中所有内容都已转换为类似 HTML 的标签。它遍历所有具有 math
类的元素,并使用 解析内容并将其渲染为实际的 HTML。
¥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 模块,一种 JavaScript 模块系统,Docusaurus 支持。我们建议使用 ES 模块 配置文件,以便更轻松地导入此类包。
¥Many official Remark/Rehype plugins are ES Modules only, a JavaScript module system, which Docusaurus supports. We recommend using an ES Modules config file to make it easier to import such packages.
接下来,导入你的插件并通过 docusaurus.config.js
中的插件或预设配置将它们添加到插件选项中:
¥Next, import your plugins and add them to the plugin options through plugin or preset config in 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],
},
},
],
],
};
Using a CommonJS config file?
如果你决定使用 CommonJS 配置文件,则可以通过动态导入和异步配置创建器功能来加载这些 ES 模块插件:
¥If you decide to use a CommonJS config file, it is possible to load those ES module plugins thanks to dynamic imports and an async config creator function:
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],
},
},
],
],
};
};
配置插件
¥Configuring plugins
一些插件可以配置并接受它们自己的选项。在这种情况下,请使用 [plugin, pluginOptions]
语法,如下所示:
¥Some plugins can be configured and accept their own options. In that case, use the [plugin, pluginOptions]
syntax, like this:
import rehypeKatex from 'rehype-katex';
export default {
presets: [
[
'@docusaurus/preset-classic',
{
docs: {
rehypePlugins: [
[rehypeKatex, {strict: false}],
],
},
},
],
],
};
你应该检查插件的文档以了解它支持的选项。
¥You should check your plugin's documentation for the options it supports.
创建新的 rehype/remark 插件
¥Creating new rehype/remark plugins
如果没有现有的包可以满足你的自定义需求,你可以创建自己的 MDX 插件。
¥If there isn't an existing package that satisfies your customization need, you can create your own MDX plugin.
下面的文章并不是创建插件的综合指南,而只是说明如何使其与 Docusaurus 一起使用。请访问 Remark 或 Rehype 文档以更深入地解释它们的工作原理。
¥The writeup below is not meant to be a comprehensive guide to creating a plugin, but just an illustration of how to make it work with Docusaurus. Visit the Remark or Rehype documentation for a more in-depth explanation of how they work.
例如,让我们创建一个访问每个 h2
标题并添加 Section X.
前缀的插件。首先,在任何地方创建插件源文件 - 你甚至可以将其发布为单独的 npm 包并按照上面的说明进行安装。我们会把我们的放在 src/remark/section-prefix.js
。remark/rehype 插件只是一个接收 options
并返回在 AST 上运行的 transformer
的函数。
¥For example, let's make a plugin that visits every h2
heading and adds a Section X.
prefix. First, create your plugin source file anywhere—you can even publish it as a separate npm package and install it like explained above. We would put ours at src/remark/section-prefix.js
. A remark/rehype plugin is just a function that receives the options
and returns a transformer
that operates on the AST.
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
中导入你的插件并像安装的插件一样使用它!
¥You can now import your plugin in docusaurus.config.js
and use it just like an installed plugin!
import sectionPrefix from './src/remark/section-prefix';
export default {
presets: [
[
'@docusaurus/preset-classic',
{
docs: {
remarkPlugins: [sectionPrefix],
},
},
],
],
};
transformer
有第二个参数 vfile
,如果你需要访问当前 Markdown 文件的路径,该参数很有用。
¥The transformer
has a second parameter vfile
which is useful if you need to access the current Markdown file's path.
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()
调用。
¥Our transformImage
plugin uses this parameter, for example, to transform relative image references to require()
calls.
Docusaurus 的默认插件将在自定义 remark 插件之前运行,这意味着图片或链接已通过 require()
调用转换为 JSX。例如,在上面的示例中,即使所有 h2
标题现在都以 Section X.
为前缀,生成的目录仍然相同,因为 TOC 生成插件是在我们的自定义插件之前调用的。如果你需要在默认插件之前处理 MDAST,请使用 beforeDefaultRemarkPlugins
和 beforeDefaultRehypePlugins
。
¥The default plugins of Docusaurus would operate before the custom remark plugins, and that means the images or links have been converted to JSX with require()
calls already. For example, in the example above, the table of contents generated is still the same even when all h2
headings are now prefixed by Section X.
, because the TOC-generating plugin is called before our custom plugin. If you need to process the MDAST before the default plugins do, use the beforeDefaultRemarkPlugins
and beforeDefaultRehypePlugins
.
export default {
presets: [
[
'@docusaurus/preset-classic',
{
docs: {
beforeDefaultRemarkPlugins: [sectionPrefix],
},
},
],
],
};
这将使生成的目录也包含 Section X.
前缀。
¥This would make the table of contents generated contain the Section X.
prefix as well.