mirror of
https://github.com/facebook/docusaurus.git
synced 2025-04-28 17:57:48 +02:00
214 lines
8.4 KiB
Text
214 lines
8.4 KiB
Text
---
|
|
id: plugins
|
|
title: MDX Plugins
|
|
description: Using MDX plugins to expand Docusaurus Markdown functionalities
|
|
slug: /markdown-features/plugins
|
|
---
|
|
|
|
Sometimes, you may want to extend or tweak your Markdown syntax. For example:
|
|
|
|
- How do I embed youtube videos using the image syntax (``)?
|
|
- 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?
|
|
|
|
And the answer is: create an MDX plugin! MDX has a built-in [plugin system](https://mdxjs.com/advanced/plugins/) 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](https://github.com/remarkjs/remark/blob/main/doc/plugins.md#list-of-plugins) or [rehype plugins](https://github.com/rehypejs/rehype/blob/main/doc/plugins.md#list-of-plugins);
|
|
- Creating remark/rehype plugins to transform the elements generated by existing MDX syntax;
|
|
- Creating remark/rehype plugins to introduce new syntaxes to MDX.
|
|
|
|
If you play with the [MDX playground](https://mdx-git-renovate-babel-monorepo-mdx.vercel.app/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](https://github.com/remarkjs/remark/)**: processes the Markdown AST.
|
|
- **[Rehype](https://github.com/rehypejs/rehype/)**: processes the Hypertext AST.
|
|
|
|
:::tip
|
|
|
|
Use plugins to introduce shorter syntax for the most commonly used JSX elements in your project. The [admonition](./markdown-features-admonitions.mdx) syntax that we offer is also generated by a [Remark plugin](https://github.com/elviswolcott/remark-admonitions), and you could do the same for your own use case.
|
|
|
|
:::
|
|
|
|
## Default plugins {#default-plugins}
|
|
|
|
Docusaurus injects [some default Remark plugins](https://github.com/facebook/docusaurus/tree/main/packages/docusaurus-mdx-loader/src/remark) during Markdown processing. These plugins would:
|
|
|
|
- Generate the table of contents;
|
|
- Add anchor links to each heading;
|
|
- Transform images and links to `require()` calls.
|
|
- …
|
|
|
|
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 {#installing-plugins}
|
|
|
|
An MDX plugin is usually an npm package, so you install them like other npm packages using npm. Take the [math plugins](./markdown-features-math-equations.mdx) as an example.
|
|
|
|
```bash npm2yarn
|
|
npm install --save remark-math@3 rehype-katex@4
|
|
```
|
|
|
|
:::note
|
|
|
|
There's recently a trend in the Remark/Rehype ecosystem to migrate to ES Modules, a new JavaScript module system, which Docusaurus doesn't support yet. Please make sure your installed plugin version is CommonJS-compatible before we officially support ESM. Alternatively, you can read about using dynamic `import()` as a workaround in the tutorial of installing [`rehype-katex`](./markdown-features-math-equations.mdx#upgrading-rehype-katex-beyond-recommended-version).
|
|
|
|
:::
|
|
|
|
<details>
|
|
<summary>How are <code>remark-math</code> and <code>rehype-katex</code> different?</summary>
|
|
|
|
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 $\KaTeX$ out with other math renderers, like MathJax (with [`rehype-mathjax`](https://github.com/remarkjs/remark-math/tree/main/packages/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 $\KaTeX$ to parse and render the content to actual HTML.
|
|
|
|
</details>
|
|
|
|
Next, add them to the plugin options through plugin or preset config in `docusaurus.config.js`:
|
|
|
|
```js title="docusaurus.config.js"
|
|
// highlight-start
|
|
const math = require('remark-math');
|
|
const katex = require('rehype-katex');
|
|
// highlight-end
|
|
|
|
module.exports = {
|
|
title: 'Docusaurus',
|
|
tagline: 'Build optimized websites quickly, focus on your content',
|
|
presets: [
|
|
[
|
|
'@docusaurus/preset-classic',
|
|
{
|
|
docs: {
|
|
// highlight-start
|
|
remarkPlugins: [math],
|
|
rehypePlugins: [katex],
|
|
// highlight-end
|
|
},
|
|
},
|
|
],
|
|
],
|
|
};
|
|
```
|
|
|
|
## Configuring plugins {#configuring-plugins}
|
|
|
|
Some plugins can be configured and accept their own options. In that case, use the `[plugin, pluginOptions]` syntax, like this:
|
|
|
|
```js title="docusaurus.config.js"
|
|
module.exports = {
|
|
presets: [
|
|
[
|
|
'@docusaurus/preset-classic',
|
|
{
|
|
docs: {
|
|
remarkPlugins: [math],
|
|
rehypePlugins: [
|
|
// highlight-next-line
|
|
[katex, {strict: false}],
|
|
],
|
|
},
|
|
},
|
|
],
|
|
],
|
|
};
|
|
```
|
|
|
|
You should check your plugin's documentation for the options it supports.
|
|
|
|
## Creating new rehype/remark plugins {#creating-new-rehyperemark-plugins}
|
|
|
|
If there isn't an existing package that satisfies your customization need, you can create your own MDX plugin.
|
|
|
|
:::note
|
|
|
|
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](https://github.com/remarkjs/remark/blob/main/doc/plugins.md#creating-plugins) or [Rehype](https://github.com/remarkjs/remark/blob/main/doc/plugins.md#creating-plugins) documentation for a more in-depth explanation of how they work.
|
|
|
|
:::
|
|
|
|
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.
|
|
|
|
```js "src/remark/section-prefix.js"
|
|
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;
|
|
```
|
|
|
|
You can now import your plugin in `docusaurus.config.js` and use it just like an installed plugin!
|
|
|
|
```js title="docusaurus.config.js"
|
|
// highlight-next-line
|
|
const sectionPrefix = require('./src/remark/section-prefix');
|
|
|
|
module.exports = {
|
|
presets: [
|
|
[
|
|
'@docusaurus/preset-classic',
|
|
{
|
|
docs: {
|
|
// highlight-next-line
|
|
remarkPlugins: [sectionPrefix],
|
|
},
|
|
},
|
|
],
|
|
],
|
|
};
|
|
```
|
|
|
|
:::tip
|
|
|
|
The `transformer` has a second parameter [`vfile`](https://github.com/vfile/vfile) which is useful if you need to access the current Markdown file's path.
|
|
|
|
```js
|
|
const plugin = (options) => {
|
|
const transformer = async (ast, vfile) => {
|
|
ast.children.unshift({
|
|
type: 'text',
|
|
value: `The current file path is ${vfile.path}`,
|
|
});
|
|
};
|
|
return transformer;
|
|
};
|
|
```
|
|
|
|
Our `transformImage` plugin uses this parameter, for example, to transform relative image references to `require()` calls.
|
|
|
|
:::
|
|
|
|
:::note
|
|
|
|
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`.
|
|
|
|
```js title="docusaurus.config.js"
|
|
module.exports = {
|
|
presets: [
|
|
[
|
|
'@docusaurus/preset-classic',
|
|
{
|
|
docs: {
|
|
// highlight-next-line
|
|
beforeDefaultRemarkPlugins: [sectionPrefix],
|
|
},
|
|
},
|
|
],
|
|
],
|
|
};
|
|
```
|
|
|
|
This would make the table of contents generated contain the `Section X.` prefix as well.
|
|
|
|
:::
|