Chomu's Blog.

>

Posts

GitHub

Next.js 에서 Markdown 파일 렌더링하기

현재 블로그를 만드는데 Next.js 를 구조를 잡고 포스트는 Markdown 파일로 작성하고 있다. 이 때 Next.js 를 이용해 Markdown 파일을 렌더링하는 방법을 정리해봤다.

목차

Markdown 렌더링

Markdown 파일을 Next.js 앱에서 렌더링 하는 방법은 Next.js 공식 문서 에서도 소개하고 있다.

MDX

해당 문서에서는 MDX 를 사용하는데, Markdown 에서 JSX 를 사용할 수 있도록 확장한 것일 뿐이므로 걱정할 필요 없다. JSX 를 쓸 때 *.js|.ts 파일의 확장자 뒤에 x 만 추가로 붙이는 것처럼, *.md 파일 뒤에 x 만 붙여 *.mdx 파일로 만들어주면 된다. *.mdx 파일로 만들면 Markdown 안에서 JSX 를 사용할 수 있기 때문에 더 다양한 기능을 사용할 수 있다.

설정

먼저 필요한 라이브러리를 설치한다.

yarn add @next/mdx @mdx-js/loader @mdx-js/react @types/mdx
# 혹은
npm install @next/mdx @mdx-js/loader @mdx-js/react @types/mdx

그리고 app/ 디렉토리와 동일한 위치에 mdx-components.tsx 파일을 생성해 다음과 같은 코드를 작성한다. 이 useMDXComponents 를 이용해 Markdown 컴포넌트를 어떻게 렌더링할 지 설정할 수 있는데, 조금 뒤에 설명하겠다.

import type { MDXComponents } from 'mdx/types'
 
export function useMDXComponents(components: MDXComponents): MDXComponents {
  return {
    ...components,
  }
}

그리고 next.config.mjs 파일을 열어 다음과 같이 설정한다.

import withMDX from "@next/mdx";
 
// ...
/** @type {import('next').NextConfig} */
const nextConfig = {
  // ...
  pageExtensions: ["js", "jsx", "mdx", "ts", "tsx"],
};
 
export default withMDX()(nextConfig);

pageExtensions 은 Next.js 에서 렌더링할 파일의 확장자를 설정하는데, 여기에 mdx 를 추가해주자. 그리고 withMDX 를 이용해 MDX 를 사용할 수 있도록 설정해주었다. 이렇게 설정하면 app/페이지/경로/page.mdx 파일을 Next.js 가 렌더링 해서 /페이지/경로 에 해당하는 페이지를 만들어준다. 일반적인 page.tsx 파일과 같은 방식으로 사용할 수 있다.

플러그인

JS 라이브러리 중에는 Markdown 렌더링을 도와주는 라이브러리가 많이 있다. 그 중 대표적인 라이브러리로는 remarkrehype 가 있다. remark 는 Markdown 을 HTML 로 파싱하고 rehype 는 파싱된 HTML 을 변환하는데 사용된다. 두 라이브러리는 플러그인을 추가해 기능을 확장시킬 수 있다.

사용법

예를 들어 사용할 플러그인이 remark-frontmatter 라고 가정하자. 그럼 먼저 라이브러리를 설치해주자.

yarn add remark-frontmatter
# 혹은
npm install remark-frontmatter

그리고 config 파일을 열어 다음과 같이 설정해주자.

import remarkFrontmatter from "remark-frontmatter";
 
// ...
 
export default withMDX({
  remarkPlugins: [remarkFrontmatter],
})(nextConfig);

이렇게 간단하게 플러그인을 추가할 수 있다! rehype 도 마찬가지로 rehypePlugins 를 이용해 플러그인을 추가할 수 있다.

추가로 옵션을 설정해야 하는 경우에는 배열로 넘겨주면 된다. 예를 들어 remark-mdx-frontmatter 라는 플러그인을 설정할 때 name: "metadata" 라는 옵션을 주는 경우 다음과 같이 설정할 수 있다.

import remarkMdxFrontmatter from "remark-mdx-frontmatter";
 
// ...
 
export default withMDX({
  remarkPlugins: [
    remarkFrontmatter,
    [remarkMdxFrontmatter, { name: "metadata" }],
  ],
})(nextConfig);

내가 사용하는 플러그인

내가 사용한 플러그인의 목록과 간단한 설명을 정리해봤다.

remark-frontmatter

remark-frontmatter는 Markdown 파일의 frontmatter 를 파싱해주는 플러그인이다. frontmatter 는 Markdown 파일의 맨 위에 --- 로 감싸진 YAML 형식의 메타데이터를 말한다. Next.js 기본 설정에서는 frontmatter 를 파싱하지 않기 때문에 만약 frontmatter 가 작성된 문서가 하나라도 있다면 이 플러그인을 꼭 사용해야 한다.

remark-mdx-frontmatter

remark-mdx-frontmatter은 상기한 remark-frontmatter 와 함께 사용하는 플러그인이다. remark-frontmatter 가 파싱해준 frontmatter 를 MDX 문서에서 내보낼 때 사용된다. 위에서 예시로 들었던 것처럼 name 옵션을 이용해 frontmatter 를 어떤 이름으로 내보낼 지 설정할 수 있다. 예시처럼 "metadata" 로 설정하면 export const metadata = { ... } 와 같은 형태로 내보내진다. 이를 Next.js 가 metadata 로 사용할 수 있기 때문에 매우 편리하다.

remark-toc

remark-toc는 목차를 반자동으로 생성해주는 플러그인이다. Markdown 파일에 ## Contents 와 같은 제목을 추가하면 해당 제목 아래에 목차가 자동으로 생성된다. heading 옵션에서 목차로 사용할 제목의 정규식을 설정할 수 있고 기본값은 "(table[ -]of[ -])?contents?|toc" 이다. 나는 기본값에 "목차" 를 추가한 "(table[ -]of[ -])?contents?|toc|목차" 로 설정했다.

remark-math

remark-math는 Markdown 파일에서 TeX를 파싱해주는 플러그인이다. $$ 로 감싸진 TeX 코드를 파싱해주는데, rehype-katex 와 함께 사용하면 수식을 렌더링할 수 있다.

rehype-katex

rehype-katexKaTeX 를 이용해 TeX 수식을 렌더링해주는 플러그인이다. remark-math 와 함께 사용해야한다. KaTeX 보다 MathJax 가 더 좋다면 rehype-mathjax 를 사용하면 된다.

rehype-pretty-code

rehype-pretty-code 는 코드 블럭을 예쁘게 만들어주는 플러그인이다. 공식 문서에도 나와 있듯이 shiki 라는 라이브러리를 사용하기 때문에 같이 설치해줘야한다. 단순한 코드 하이라이팅 뿐만이 아니라 다양한 기능을 지원하니 공식 문서를 꼭 읽어보자.

rehype-slug

rehype-slug 는 제목마다 id 값을 자동으로 추가해준다. 제목마다 id 값이 추가되므로 URL 프라그먼트 식별자를 사용해 문서의 제목으로 바로 이동할 수 있는 링크를 만들 수 있다.

rehype-autolink-headings

rehype-autolink-headings 는 제목마다 자동으로 앵커를 추가해준다. 제목을 클릭하면 URL 프라그먼트 식별자로 바로 이동할 수 있고 제목에서 링크를 복사해 해당 제목으로 바로 이동할 수 있는 링크를 가져올 수 있다.

마무리

Next.js 에서 Markdown 파일을 렌더링하는 방법을 정리해봤다. 추후에 다른 플러그인을 사용하게 되면 추가해 놓겠다.