MDX와 리액트
마크다운에서 JSX 사용하기
도큐사우루스는 MDX v1를 기본 지원합니다. MDX를 기반으로 마크다운 파일 내에 JSX를 작성해서 리액트 컴포넌트를 표현할 수 있습니다.
도큐사우루스는 MDX를 사용해 .md
, .mdx
파일을 모두 구문 분석하지만 일부 구문은 서드파티 도구에서 약간 다르게 처리됩니다. 좀 더 정확한 구문 해석과 에디터 지원을 위해 MDX 문법을 포함한 .mdx
파일 확장자를 사용하는 것을 권장합니다.
MDX 문서에서 MDX로 할 수 있는 더 많은 흥미로운 기능을 찾아볼 수 있습니다.
컴포넌트 내보내기
MDX 파일 내에서 사용자 지정 컴포넌트를 정의하려면 내보내기를 수행해야 합니다. export
로 시작하는 단락은 일반 문장이 아니라 컴포넌트로 구문 분석됩니다.
export const Highlight = ({children, color}) => (
<span
style={{
backgroundColor: color,
borderRadius: '2px',
color: '#fff',
padding: '0.2rem',
}}>
{children}
</span>
);
<Highlight color="#25c2a0">도큐사우루스 초록</Highlight>과 <Highlight color="#1877F2">페이스북 파랑</Highlight>은 내가 좋아하는 색입니다.
**마크다운**을 _JSX_와 같이 사용할 수 있습니다!
리액트 컴포넌트와 마크다운 문법이 어떻게 마크업 코드로 변환되는지 확인할 수 있습니다.
마크다운을 JSX와 같이 사용할 수 있습니다!
모든 문서 파일은 MDX를 사용해 구문 분석되므로 HTML처럼 보이는 모든 것은 실제로는 JSX입니다. 그래서 컴포넌트를 인라인 스타일로 설정해야 하는 경우 JSX 형식을 따르며 style 오브젝트를 지정해주어야 합니다.
/* 이렇게 쓰지 말고: */
<span style="background-color: red">Foo</span>
/* 이렇게 쓰세요: */
<span style={{backgroundColor: 'red'}}>Foo</span>
이 부분은 도큐사우루스 1과 달라진 점입니다. 자세한 내용은 v1에서 v2로 이전하기를 참고하세요.
MDX는 CommonMark와 100% 호환을 보장하지는 않습니다. MDX playground에서 여러분이 사용하는 문법이 유효한 MDX 구문인지 확인해보세요.
컴포넌트 가져오기
다른 파일에 설정한 사용자 지정 컴포넌트나 npm으로 설치한 서드파티 컴포넌트를 가져올 수도 있습니다.
<!-- 도큐사우루스 테마 컴포넌트 -->
import TOCInline from '@theme/TOCInline';
<!-- 외부 컴포넌트 -->
import Button from '@mui/material/Button';
<!-- 사용자 지정 컴포넌트 -->
import BrowserWindow from '@site/src/components/BrowserWindow';
마크다운 내에서 컴포넌트를 선언하는 것은 간단한 경우에는 매우 편리하지만 편집기의 제한된 지원이나 구문 분석 오류 위험, 낮은 재사용성으로 인해 유지 관리가 어려워질 수 있습니다. 컴포넌트에 복잡한 JS 로직이 포함된 경우 별도의 .js
파일을 사용하세요.
import React from 'react';
export default function Highlight({children, color}) {
return (
<span
style={{
backgroundColor: color,
borderRadius: '2px',
color: '#fff',
padding: '0.2rem',
}}>
{children}
</span>
);
}
import Highlight from '@site/src/components/Highlight';
<Highlight color="#25c2a0">도큐사우루스 초록</Highlight>
많은 파일에서 같은 컴포넌트를 사용하는 경우 모든 곳에서 가져올 필요는 없습니다. 전역 스코프에 추가하는 것이 좋습니다. 아래 내용을 참고하세요.
MDX 컴포넌트 스코프
컴포넌트 가져오기와 컴포넌트 내보내기 외에도 MDX에서 컴포넌트를 사용하는 세 번째 방법은 전역 스코프에 등록하는 것입니다. 그러면 import 구문을 사용하지 않고 모든 MDX 파일에서 자동으로 사용할 수 있습니다.
예를 들어 이런 MDX 파일이 주어진다면
- a
- list!
And some <Highlight>custom markup</Highlight>...
ul
, li
, p
, Highlight
요소를 포함하는 리액트 컴포넌트로 컴파일됩니다. Highlight
는 네이티브 HTML 요소가 아니므로 여러분이 리액트 컴포넌트를 구현해야 합니다.
도큐사우루스에서 MDX 컴포넌트 스코프는 @theme/MDXComponents
파일에 의해 제공됩니다. @theme/
별칭으로 내보내는 대부분 다른 것들과 다르게 그 자체만 보면 리액트 컴포넌트가 아닙니다. 하지만 Highlight
와 같은 태그 이름에서 사용자가 구현한 리액트 컴포넌트까지의 기록이라 할 수 있습니다.
컴포넌트를 스위즐링하면 구현된 모든 태그를 찾을 수 있으며 (마크다운 코드 블록을 렌더링하는 데 사용되는) @theme/MDXComponents/Code
와 같은 각 하위 컴포넌트를 스위즐링해서 구현체를 추가적으로 커스터마이징할 수 있습니다.
추가적인 태그 이름(위에서 <Highlight>
태그와 같은)을 등록하려면 @theme/MDXComponents
를 감싸는 것 형식으로 처리할 수 있으며 기존 매핑을 모두 유지할 필요는 없습니다. swizzle CLI는 컴포넌트가 아닌 파일을 감싸는 것을 허용하지 않으므로 수작업으로 래퍼를 생성해야 합니다.
import React from 'react';
// 원본 mapper 가져오기
import MDXComponents from '@theme-original/MDXComponents';
import Highlight from '@site/src/components/Highlight';
export default {
// 기본 mapping 재사용
...MDXComponents,
// "<Highlight>" 태그를 여러분이 만든 Highlight 컴포넌트에 매핑하세요.
// `Highlight`는 MDX에서 `<Highlight>`로 전달된 모든 속성을 수신합니다.
Highlight,
};
이제 import 구문을 사용하지 않고 모든 페이지에서 <Highlight>
를 자유롭게 사용할 수 있습니다.
I can conveniently use <Highlight color="#25c2a0">Docusaurus green</Highlight> everywhere!
I can conveniently use Docusaurus green everywhere!
우리는 의도적으로 Highlight
와 같은 대문자로 시작하는 태그 이름을 사용합니다.
MDX v2 이상(도큐사우루스 v3 이상)부터 소문자로 시작하는 태그 이름은 항상 기본 HTML 요소로 렌더링되며 사용자가 제공하는 컴포넌트 매핑이 적용되지 않습니다.
이 기능은 wrapper provider에서 지원하는 기능입니다. 리액트 페이지에서 마크다운을 가져오는 경우 MDXContent
테마 컴포넌트를 통해 해당 provider를 직접 제공해주어야 합니다.
import React from 'react';
import FeatureDisplay from './_featureDisplay.mdx';
import MDXContent from '@theme/MDXContent';
export default function LandingPage() {
return (
<div>
<MDXContent>
<FeatureDisplay />
</MDXContent>
</div>
);
}
가져온 MDX를 MDXContent
로 감싸지 않으면 전역 스코프를 사용할 수 없습니다.
마크다운과 JSX 상호 운용성
도큐사우루스 v2는 MDX v1을 사용하고 있는데 콘텐츠가 마크다운으로 적절하게 구문 분석되지 못하는 경우가 있습니다. MDX playground에서 여러분이 사용하는 문법이 유효한 MDX 구문인지 확인해보세요.
구문 분석 실패 예시
JSX 태그로 시작하는 단락은 완전히 JSX 문자열로 표시됩니다.
- Problem
- Workaround
<span style={{color: 'red'}}>Highlighted text</span> but afterwards _Markdown_ **doesn't work**
줄의 나머지 부분에 JSX를 사용하거나 일반 텍스트를 접두어로 사용하세요.
<span style={{color: 'red'}}>Use JSX for the paragraph</span> to stop <i>worrying about</i> <b>Markdown</b>
​<span style={{color: 'red'}}>← This is a zero-width space</span> and afterwards <i>Markdown</i> <b>works</b>
← This is a zero-width space and afterwards Markdown works
JSX 태그 내에서 마크다운은 작동하지 않습니다.
- Problem
- Workaround
<span style={{color: 'red'}}>**Bold doesn't work**</span>
JSX 태그 내에서 JSX를 사용하거나 마크다운을 외부 레이어로 이동합니다.
<span style={{color: 'red'}}><b>Bold now works</b></span>
**<span style={{color: 'red'}}>Bold now works</span>**
Bold now works
JSX 태그 바로 아래에 있는 텍스트는 JSX 텍스트로 표시됩니다.
- Problem
- Workaround
<div style={{color: 'red'}}>
**Bold still doesn't work**
</div>
새 줄을 추가합니다.
<div style={{color: 'red'}}>
**Bold now works**
</div>
Bold now works
4개의 공백문자로 들여쓴 마크다운 텍스트는 코드 블록으로 표시됩니다.
- Problem
- Workaround
<div style={{color: 'red'}}>
You may think I'm just some text...
</div>
You may think I'm just some text...
들여쓰지 마세요.
<div style={{color: 'red'}}>
Now I'm actually just text
</div>
Now I'm actually just text
코드 스니펫 가져오기
Webpack raw-loader 덕분에 컴포넌트 정의가 포함된 파일을 가져올 수 있을 뿐 아니라 모든 코드 파일을 텍스트 형태로 가져와서 코드 블록에 삽입할 수 있습니다. raw-loader
를 사용하기 위해서 먼저 여러분의 프로젝트에 설치해주어야 합니다.
- npm
- Yarn
- pnpm
npm install --save raw-loader
yarn add raw-loader
pnpm add raw-loader
이제 아래와 같은 형태로 다른 파일에서 코드 스니펫을 가져올 수 있습니다.
import CodeBlock from '@theme/CodeBlock';
import MyComponentSource from '!!raw-loader!./myComponent';
<CodeBlock language="jsx">{MyComponentSource}</CodeBlock>
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import React, {useState} from 'react';
export default function MyComponent() {
const [bool, setBool] = useState(false);
return (
<div>
<p>MyComponent rendered !</p>
<p>bool={bool ? 'true' : 'false'}</p>
<p>
<button onClick={() => setBool((b) => !b)}>toggle bool</button>
</p>
</div>
);
}
<CodeBlock>
컴포넌트에 대한 자세한 내용은 JSX에서 코드 블록 사용하기를 참고하세요.
마크다운에서 3개의 억음부호```
대신 <CodeBlock>
을 사용해야 합니다. 억음부호를 사용하면 그 내용을 그대로 보여주는데 우리는 가져온 텍스트를 여기에 삽입하기를 원하기 때문입니다.
이 기능은 아직 실험중이며 향후 API 변경 사항이 적용될 수 있습니다.
마크다운 가져오기
마크다운 파일을 컴포넌트처럼 사용할 수 있습니다. 마크다운 파일 또는 리액트 페이지로 가져오기를 할 수 있습니다.
규칙에 따라 _
파일명 접두사를 사용할 때 문서 페이지가 생성되지 않는다면 마크다운 파일이 다른 파일에서 가져온 "일부분"임을 의미합니다.
<span>Hello {props.name}</span>
This is text some content from `_markdown-partial-example.mdx`.
import PartialExample from './_markdown-partial-example.mdx';
<PartialExample name="Sebastien" />
_markdown-partial-example.md
에서 가져온 텍스트입니다.
이렇게 하면 여러 페이지에서 콘텐츠를 재사용할 수 있으며 자료의 중복을 방지할 수 있습니다.
현재는 가져온 마크다운 파일의 제목이 목차에 포함되지 않습니다. 기술적인 제약이며 해결하기 위해 노력하고 있습니다(관련 이슈를 참고하세요).
사용 가능한 내보내기 형식
MDX 페이지 내에서는 다음 변수를 전역으로 사용할 수 있습니다.
frontMatter
: 문자열 키와 값으로 구성된 프런트 매터toc
: 트리 형태의 제목 목록인 목차. 좀 더 구체적인 사용 사례는 인라인 TOC을 참고하세요.contentTitle
: 마크다운 텍스트의 첫 번째h1
제목. 항목이 없는 경우(예를 들어 프런트 매터에서 title 항목이 없는 경우)undefined
로 처리됩니다.
import TOCInline from '@theme/TOCInline';
import CodeBlock from '@theme/CodeBlock';
The table of contents for this page, serialized:
<CodeBlock className="language-json">{JSON.stringify(toc, null, 2)}</CodeBlock>
The front matter of this page:
<ul>
{Object.entries(frontMatter).map(([key, value]) => <li key={key}><b>{key}</b>: {value}</li>)}
</ul>
<p>The title of this page is: <b>{contentTitle}</b></p>
The table of contents for this page, serialized:
[
{
"value": "마크다운에서 JSX 사용하기",
"id": "using-jsx-in-markdown",
"level": 2
},
{
"value": "컴포넌트 내보내기",
"id": "exporting-components",
"level": 3
},
{
"value": "컴포넌트 가져오기",
"id": "importing-components",
"level": 3
},
{
"value": "MDX 컴포넌트 스코프",
"id": "mdx-component-scope",
"level": 3
},
{
"value": "마크다운과 JSX 상호 운용성",
"id": "markdown-and-jsx-interoperability",
"level": 3
},
{
"value": "코드 스니펫 가져오기",
"id": "importing-code-snippets",
"level": 2
},
{
"value": "마크다운 가져오기",
"id": "importing-markdown",
"level": 2
},
{
"value": "사용 가능한 내보내기 형식",
"id": "available-exports",
"level": 2
}
]
The front matter of this page:
- id: react
- description: MDX를 사용해 도큐사우루스 마크다운 문서 내에서 리액트의 강력한 기능을 활용할 수 있습니다.
- slug: /markdown-features/react
The title of this page is: MDX와 리액트