마크다운 (Markdown)은 마크업 언어 (Markup Language)의 하나로, 여는 태그와 닫는 태그 쌍으로 이루어진 HTML 태그와는 달리 간단한 문법으로 문서를 양식화 할 수 있도록 해줍니다.
개발 프로젝트 등에서 우리가 흔히 마주치는 README.md
파일 과 같이 .md
또는 .markdown
파일은 이러한 마크다운 문서입니다.
마크다운의 기본적인 문법은 아래 Github의 공식 문서에서 확인 할 수 있습니다.
https://guides.github.com/features/mastering-markdown/
MDX는 마크다운의 상위 집합으로, 마크다운 파일 내에서 JSX를 직접 작성할 수 있게 해줍니다. 이를 통해 동적인 상호작용을 추가하거나 React 컴포넌트를 콘텐츠에 쉽게 삽입할 수 있습니다.
Next.js에서는 로컬 (app 하위 폴더 등)에 MDX 파일을 위치시켜 자동으로 변환해 주거나, 서버나 외부 저장소에서 동적으로 가져와 처리하는 원격 MDX도 지원합니다.
원격 MDX를 지원해주는 여러가지 패키지가 있습니다. 그 중 next-mdx-remote 패키지가 주로 사용됩니다.
이러한 패키지는 MDX 파일을 불러와 분석하여 HTML 형태로 변환해 주는 역할을 합니다.
MDX Remote 패키지는 크게 remark
플러그인와 rehype
플러그인을 지원합니다.
remark
는 마크다운 문서를 적절한 HTML
로 변환해 주는 역할을 합니다.rehype
는 변환된 HTML
을 꾸며주거나 후처리 해주는 역할을 합니다.이번 가이드에서는 여러 rehype
플러그인들 중 코드 블럭을 꾸며줄 수 있는 rehype-pretty-code 플러그인에 좀 더 집중해서 설명할 것입니다.
이 가이드는 MDX Remote
패키지를 이용하여 마크다운 파일을 HTML로 변환한 후, prose
CSS 클래스 문서를 꾸며 줄 때, Tailwind Typography 플러그인을 사용하는 것을 가정하겠습니다.
우선, rehype-pretty-code
패키지는 다음과 같이 설치합니다.
npm install rehype-pretty-code shiki
rehype-pretty-code
플러그인은 shiki
(Syntax highligher)를 기반으로 하기 때문에 위와 같이 함께 설치해 줍니다.
shiki
패키지를 설치하면, 코드 블럭에 대한 여러가지 테마 파일 번들도 함께 설치가 됩니다.
이제 다음과 같이 페이지 또는 컴포넌트를 구성해 줍니다.
// ...중략...
import rehypePrettyCode from "rehype-pretty-code"
export const MDXElement = ({ content }: { content: string }) => {
return (
<article className="prose">
<MDXRemote
source={content}
options={{
mdxOptions: {
remarkPlugins: [
remarkGfm,
remarkBreaks,
],
rehypePlugins: [
[
// @ts-ignore
rehypePrettyCode,
{
theme: { dark: "github-dark", light: "github-light" },
},
],
// ... 중략 ...
],
},
}}
components={MdxComponents}
/>
</article>
)
}
위 코드에서, MDXRemote
컴포넌트의 rehypePlugins
속성으로 rehype
적용할 플러그인들을 나열하면 됩니다.
rehypePlugins
속성은 플러그인 배열을 넣어주면 되며, [[플러그인, {옵션},], ...]
과 같은 형태로 작성해주면 됩니다.
이번 가이드에서는 코드 블럭을 꾸며주기 위해 rehypePrettyCode
플러그인을 넣어주었습니다.
(참고적으로, Typography
가 잘 적용되기 위해서는 MDX 엘리먼트를 감싸주는 부모 엘리먼트의 클래스에 prose
를 추가해 줘야 합니다. Typography
가 prose
클래스 하위 엘리먼트에 적용되기 때문입니다.)
위 코드에서 rehypePrettyCode
의 옵션으로 theme
를 지정했습니다. theme
는 일반 문자열 값 (테마 이름)을 입력할 수 있으며, 위와 같이 컬러 모드에 따른 테마를 지정해 줄 수 있습니다.
테마 이름은 https://shiki.style/themes 에서 확인할 수 있습니다.
rehype-pretty-code
플러그인에서는 아래와 같이 컬러 모드에 따른 테마를 각각 지정할 수 있습니다.
{
theme: { dark: "github-dark", light: "material-theme" },
},
이렇게 지정하기만 하면 제대로 코드 블럭을 꾸며주지 못합니다.
컬러모드에 따라 변경되도록 global.css
파일을 수정해 줘야 합니다.
rehype-pretty-code
플러그인 공식 문서에서 멀티 테마 지정에 따른 CSS 설정에 대해 설명되어 있는데, TailwindCSS v3에 맞춰져 있습니다.[data-theme*=" "]
부분이 문제를 발생시킵니다.)라이트 모드와 다크모드에 따라 코드 블럭의 테마를 변경하고자 하면, 아래와 같이 global.css
파일에 추가해 주면 됩니다.
.prose pre[data-theme],
.prose code[data-theme],
.prose code[data-theme] span {
color: var(--shiki-dark);
background-color: var(--shiki-dark-bg);
}
html.dark .prose pre[data-theme],
html.dark .prose code[data-theme],
html.dark .prose code[data-theme] span {
color: var(--shiki-light);
background-color: var(--shiki-light-bg);
}
위와 같이 변경해 주면 정상적으로 CSS 구문이 파싱되어 Next.js 빌드 시 오류가 발생하는 것을 방지할 수 있고, 정상적으로 컬러 모드에 따라 코드 블럭의 테마가 적용됩니다.
Tailwind Typography 플러그인의 기본 인라인 코드 블럭은 우리가 일반적으로 보던 인라인 코드 블럭과 달리 심심한 감이 있고, 원치않는 `
(Grave) 문자도 그대로 표시됩니다.
따라서 아래와 같이 global.css
파일에 추가해 주면 우리가 원하는대로 인라인 코드 블럭을 꾸밀 수 있습니다.
/* ` TailwindCSS의 apply를 이용해 스타일 적용하기 */
.prose :not(pre)>code {
@apply text-neutral-600 bg-neutral-50 rounded-sm py-[0.2rem] px-[0.4rem] mr-[0.1rem] dark:bg-neutral-950 dark:text-neutral-200;
}
/* ` 문자 감추기 */
.prose :where(code):not(:where([class~="not-prose"], [class~="not-prose"] *)):before,
.prose :where(code):not(:where([class~="not-prose"], [class~="not-prose"] *)):after {
content: "";
display: none;
}
위 코드에서 text-neutral-600
, bg-neutral-50
, dark:bg-neutral-950
, dark:text-neutral-200
부분들은 https://tailwindcss.com/docs/colors 를 참고하여 적절하게 수정하시면 됩니다.
물론, 이외에도 취향에 맡게 padding
이나 margin
등을 수정하여 적용하셔도 됩니다.
마크다운 (MD
또는 MDX
) 파일의 코드 영역을 꾸며줄 때 rehype-pretty-code
과 같은 플러그인을 많이 사용합니다.
기본 코드 블럭 테마, 컬러모드에 따른 테마 등을 적용할 수 있고, 입맛에 맞춰 적절하게 수정할 수도 있습니다.
다만, 개발 편의를 위해 다양한 패키지를 사용할 수 밖에 없는데, 패키지들의 버전 업에 따른 상호 의존성이나 변경 사항등에 대해 꼼꼼하게 점검하는 습관을 가지는 것이 중요하겠습니다.
문의사항이나 보완사항은 댓글로 남겨주시기 바랍니다.
감사합니다.