MDX 플러그인
간혹 마크다운 구문을 확장하거나 변경할 수 있습니다. 예를 들면 아래와 같은 형식입니다.
- image 구문(
![](https://youtu.be/yKNxeF4KMsY)
)을 사용해 유튜브 동영상을 삽입하려면 어떻게 해야 하나요? - 소셜 카드처럼 자체 라인에 있는 링크 스타일을 다르게 지정하려면 어떻게 해야 하나요?
- 모든 페이지에 저작권 표시를 하려면 어떻게 하나요?
해결책은 MDX 플러그인을 만드는 겁니다! MDX는 마크다운 파일을 구문분석하고 JSX로 변환하는 방식을 사용자가 지정할 수 있는 내장 플러그인 시스템이 있습니다. MDX 플러그인의 세 가지 일반적인 사용 사례는 다음과 같습니다.
- 기존 remark plugins 또는 rehype plugins을 사용합니다.
- 기존 MDX 구문으로 생성된 요소를 변환하기 위한 remark/rehype 플러그인을 만듭니다.
- MDX에 새로운 구문을 도입하기 위한 remark/rehype 플러그인을 만듭니다.
MDX 플레이그라운드에서 확인하고 있다면 MDX를 JSX로 변환 시 마크다운 AST(MDAST), 하이퍼텍스트 AST(HAST) 두 개의 중간 단계가 있다는 것을 확인할 수 있습니다. MDX 플러그인 또한 두 가지 형태입니다.
플러그인을 사용해 프로젝트에서 가장 일반적으로 사용하는 JSX 요소를 좀 더 짧은 구문으로 만들 수 있습니다. 도큐사우루스에서 사용하는 준수 사항 구문은 Remark 플러그인으로 만들어지며 여러분도 여러분만의 준수 사항을 위한 플러그인을 사용할 수 있습니다.
기본 플러그인
도큐사우루스는 마크다운 처리를 위해 몇 가지 기본 Remark 플러그인을 사용합니다. 이런 플러그인은 다음 작업을 처리합니다.
- 컨텐츠 테이블 생성
- 각 제목에 링크 추가
- 이미지와 링크를
require()
호출로 변환 - …
이들은 모두 Remark 플러그인의 일반적인 사용 사례이며 여러분이 원하는 형태의 플러그인 개발 시 참고할 수 있습니다.
플러그인 설치하기
MDX 플러그인은 npm 패키지 형태로 제공됩니다. npm을 사용해 다른 npm 패키지처럼 설치할 수 있습니다. math 플러그인이라면 아래와 같이 설치합니다.
- npm
- Yarn
- pnpm
npm install --save remark-math@3 rehype-katex@4
yarn add remark-math@3 rehype-katex@4
pnpm add remark-math@3 rehype-katex@4
최근 Remark/Rehype 생태계는 도큐사우루스에서 아직 지원하지 않는 새로운 자바스크립트 모듈 시스템인 ES 모듈로 마이그레이션하는 추세가 있습니다. ESM을 공식적으로 지원하기 전에는 설치된 플러그인 버전이 CommonJS와 호환되는지 확인하세요. 또는 rehype-katex
설치 튜토리얼에서 해결책으로 동적 import()
사용에 대한 가이드를 찾아볼 수 있습니다.
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.
그런 다음 docusaurus.config.js
에서 플러그인 또는 사전 설정 구성을 플러그인 옵션에 추가합니다.
const math = require('remark-math');
const katex = require('rehype-katex');
module.exports = {
title: 'Docusaurus',
tagline: 'Build optimized websites quickly, focus on your content',
presets: [
[
'@docusaurus/preset-classic',
{
docs: {
remarkPlugins: [math],
rehypePlugins: [katex],
},
},
],
],
};
플러그인 설정하기
Some plugins can be configured and accept their own options. In that case, use the [plugin, pluginOptions]
syntax, like this:
module.exports = {
presets: [
[
'@docusaurus/preset-classic',
{
docs: {
remarkPlugins: [math],
rehypePlugins: [
[katex, {strict: false}],
],
},
},
],
],
};
You should check your plugin's documentation for the options it supports.
새로운 rehype/remark 플러그인 만들기
If there isn't an existing package that satisfies your customization need, you can create your own MDX plugin.
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.
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!
const sectionPrefix = require('./src/remark/section-prefix');
module.exports = {
presets: [
[
'@docusaurus/preset-classic',
{
docs: {
remarkPlugins: [sectionPrefix],
},
},
],
],
};
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;
};
Our transformImage
plugin uses this parameter, for example, to transform relative image references to require()
calls.
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
.
module.exports = {
presets: [
[
'@docusaurus/preset-classic',
{
docs: {
beforeDefaultRemarkPlugins: [sectionPrefix],
},
},
],
],
};
This would make the table of contents generated contain the Section X.
prefix as well.