
Next.js 블로그: unified, remark & rehype 개념 정리
Next.js MDX 블로그 구축 시 사용되는 Unified 생태계와 remarkPlugins와 rehypePlugins 추천 목록과 실제 적용 방법을 상세히 다룹니다.
시작하며
Next.js로 블로그를 구축하면서 MDX를 활용하려고 하신다면, 필연적으로 만나게 되는 것이 바로 unified 생태계입니다. 처음에는 복잡해 보이는 이 도구들이 어떻게 동작하는지, 그리고 remark와 rehype 플러그인들을 어떻게 활용하면 좋을지 정리해보았습니다. 이 글을 통해 MDX 블로그 구축에 필요한 핵심 개념들을 이해하고, 실제로 적용할 수 있는 플러그인들을 소개하겠습니다.
Unified 생태계와 AST
Unified는 텍스트를 처리하는 도구들의 집합체입니다. 콘텐츠를 파싱하고, 변환하고, 컴파일하는 전체 과정을 하나의 일관된 인터페이스로 관리할 수 있게 해주는 프레임워크입니다.
AST(Abstract Syntax Tree)란?
AST는 소스 코드의 구조를 트리 형태로 표현한 자료구조입니다. Unified 생태계에서는 텍스트를 AST로 변환하여 처리한 후, 다시 원하는 형태로 출력하는 파이프라인 방식을 사용합니다.
Unified의 핵심 개념
Unified는 플러그인 기반 아키텍처를 통해 다양한 형식의 텍스트를 처리합니다. 주요 특징은 다음과 같습니다.
- 파이프라인 방식: 입력 → 파싱 → 변환 → 출력의 과정을 체인 형태로 연결
- 플러그인 시스템: 각 단계에서 플러그인을 통해 기능 확장
- AST 기반 처리: 모든 변환이 Abstract Syntax Tree를 통해 이루어짐
- 생태계 통합: remark, rehype, retext 등 다양한 프로세서가 unified 위에서 동작
Unified 생태계의 AST 처리 과정
Markdown → [remark] → mdast → [remark-rehype] → hast → [rehype] → HTML
Unified는 이러한 변환 과정을 관리하는 인터페이스를 제공합니다. 텍스트를 파싱하고, AST를 변환하고, 최종 결과물을 생성하는 전체 파이프라인을 하나의 일관된 API로 다룰 수 있게 해줍니다.
remark는 Markdown을 mdast(Markdown AST)로 변환하고 처리하는 도구이며, rehype는 HTML을 hast(HTML AST)로 변환하고 처리하는 도구입니다. 이 두 도구를 연결하면 Markdown에서 HTML까지의 완전한 변환 파이프라인을 구성할 수 있습니다.
Unified 생태계의 주요 도구들
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ remark │ │ rehype │ │ retext │
│ (Markdown) │ │ (HTML) │ │ (Text) │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
└───────────────────┴───────────────────┘
│
┌────┴────┐
│ unified │
└─────────┘
이 중에서 MDX 블로그 구축에는 주로 remark(Markdown 처리)와 rehype(HTML 처리)를 사용합니다.
Unified로 콘텐츠가 변환되는 과정
실제로 Unified를 통해 콘텐츠가 어떻게 변환되는지 예시를 통해 살펴보겠습니다.
# 입력 (Markdown)
## Hello **World**!
- 첫 번째 항목
- [링크](https://example.com)
↓ remark-parse (Markdown → mdast)
// AST (Abstract Syntax Tree)
{
type: 'root',
children: [
{
type: 'heading',
depth: 2,
children: [
{ type: 'text', value: 'Hello ' },
{ type: 'strong', children: [{ type: 'text', value: 'World' }] },
{ type: 'text', value: '!' }
]
},
{
type: 'list',
children: [
{ type: 'listItem', children: [{ type: 'text', value: '첫 번째 항목' }] },
{ type: 'listItem', children: [
{ type: 'link', url: 'https://example.com', children: [{ type: 'text', value: '링크' }] }
]}
]
}
]
}
↓ remark-rehype (mdast → hast)
<!-- 최종 출력 (HTML) -->
<h2>Hello <strong>World</strong>!</h2>
<ul>
<li>첫 번째 항목</li>
<li><a href="https://example.com">링크</a></li>
</ul>
이렇게 Unified는 텍스트를 구조화된 데이터(AST)로 변환한 후, 각 단계에서 플러그인을 통해 변형하고, 최종적으로 원하는 형태로 출력합니다.
Next.js에서 MDX 블로그 구축하기
Next.js에서 MDX 블로그를 구축하는 방법은 크게 세 가지가 있습니다. 각각의 특징과 장단점을 살펴보겠습니다.
1. Unified 직접 사용하기
가장 유연하고 세밀한 제어가 가능한 방법입니다. unified 생태계의 도구들을 직접 조합하여 파이프라인을 구성합니다.
import rehypeStringify from "rehype-stringify"
import remarkGfm from "remark-gfm"
import remarkParse from "remark-parse"
import remarkRehype from "remark-rehype"
import { unified } from "unified"
const processor = unified()
.use(remarkParse)
.use(remarkGfm)
.use(remarkRehype)
.use(rehypeStringify)
const html = await processor.process(markdown)
직접 파이프라인을 구성하므로 완전한 커스터마이징이 가능하지만, 초기 설정이 복잡하고 MDX의 JSX 컴포넌트 처리를 직접 구현해야 합니다.
2. next-mdx-remote-client/rsc 사용하기
서버 컴포넌트와 함께 사용하기 최적화된 라이브러리입니다. 현재 가장 인기 있는 선택지 중 하나입니다.
import { MDXRemote } from "next-mdx-remote-client/rsc"
export default async function Post({ source }) {
return (
<MDXRemote
source={source}
options={{
mdxOptions: {
remarkPlugins: [remarkGfm],
rehypePlugins: [rehypeHighlight],
},
}}
components={customComponents}
/>
)
}
서버 컴포넌트에서 MDX를 처리하므로 번들 크기가 작고, 빌드 타임이 아닌 런타임에 MDX를 처리할 수 있어 동적 콘텐츠에 유리합니다.
3. @next/mdx 사용하기
Next.js의 공식 MDX 지원 패키지입니다. webpack 설정을 통해 MDX 파일을 직접 임포트할 수 있게 해줍니다.
// next.config.js
import createMDX from "@next/mdx"
const withMDX = createMDX({
options: {
remarkPlugins: [],
rehypePlugins: [],
},
})
export default withMDX(nextConfig)
하지만 Turbopack과의 호환성 문제가 있고, 빌드 타임에 모든 MDX를 처리해야 하는 제약이 있습니다. 따라서 현재로서는 1번이나 2번 방법을 추천합니다.
추천 Remark 플러그인
실제 블로그에서 유용하게 사용할 수 있는 remark 플러그인들을 소개합니다.
remark-gfm
GitHub Flavored Markdown을 지원합니다.
# 입력
- [x] 완료된 작업
- [ ] 진행 중
| 제목 | 내용 |
| ------ | ---- |
| 데이터 | 값 |
~~취소선~~
# 출력
✅ 완료된 작업 ☐ 진행 중
<table>
<thead>
<tr>
<th>제목</th>
<th>내용</th>
</tr>
</thead>
<tbody>
<tr>
<td>데이터</td>
<td>값</td>
</tr>
</tbody>
</table>
<del>취소선</del>
remark-frontmatter
YAML frontmatter를 파싱합니다. Frontmatter는 마크다운 파일 상단에 위치한 메타데이터 블록으로, 제목, 날짜, 태그 등의 정보를 담습니다.
# 입력
---
title: 블로그 포스트
date: 2024-12-15
tags: [Next.js, MDX]
---
본문 내용...
메타데이터를 추출하여 별도로 활용할 수 있습니다.
4. remark-breaks
줄바꿈을 <br>
로 변환합니다.
# 입력
첫 번째 줄
두 번째 줄
# 출력 첫 번째 줄<br />
두 번째 줄
5. remark-emoji
이모지 코드를 실제 이모지로 변환합니다.
# 입력
:smile: :heart: :rocket:
# 출력
😄 ❤️ 🚀
추천 Rehype 플러그인
HTML 처리와 최적화를 위한 rehype 플러그인들입니다.
rehype-highlight / rehype-prism-plus
코드 블록에 구문 강조를 추가합니다.
// 입력
const greeting = "Hello, World!"
console.log(greeting)
<!-- 출력 (스타일 적용) -->
<pre><code class="language-javascript">
<span class="token keyword">const</span>
<span class="token variable">greeting</span>
<span class="token operator">=</span>
<span class="token string">"Hello, World!"</span>
</code></pre>
rehype-slug
헤딩에 자동으로 ID를 추가합니다.
<!-- 입력 -->
<h2>섹션 제목</h2>
<!-- 출력 -->
<h2 id="섹션-제목">섹션 제목</h2>
rehype-autolink-headings
헤딩에 앵커 링크를 추가합니다.
<!-- 입력 -->
<h2 id="섹션">제목</h2>
<!-- 출력 -->
<h2 id="섹션">
<a href="#섹션" aria-hidden="true">🔗</a>
제목
</h2>
rehype-lazy-images
이미지에 lazy loading 속성을 추가합니다.
<!-- 입력 -->
<img src="image.jpg" alt="설명" />
<!-- 출력 -->
<img src="image.jpg" alt="설명" loading="lazy" />
실제 적용 예시
이 모든 플러그인들을 실제 Next.js 블로그에 적용하는 방법입니다.
import { MDXRemote } from "next-mdx-remote-client/rsc"
import rehypeAutolinkHeadings from "rehype-autolink-headings"
import rehypeHighlight from "rehype-highlight"
import rehypeLazyImages from "rehype-lazy-images"
import rehypeSlug from "rehype-slug"
import remarkBreaks from "remark-breaks"
import remarkEmoji from "remark-emoji"
import remarkFrontmatter from "remark-frontmatter"
import remarkGfm from "remark-gfm"
export async function renderMDX(source) {
return (
<MDXRemote
source={source}
options={{
mdxOptions: {
remarkPlugins: [
remarkGfm,
remarkFrontmatter,
remarkBreaks,
remarkEmoji,
],
rehypePlugins: [
rehypeHighlight,
rehypeSlug,
[
rehypeAutolinkHeadings,
{
behavior: "prepend",
properties: { className: "anchor-link" },
},
],
rehypeLazyImages,
],
},
}}
components={customComponents}
/>
)
}
마치며
Unified 생태계와 remark, rehype는 처음에는 복잡해 보일 수 있지만, 한 번 이해하고 나면 매우 강력한 도구입니다. 각 플러그인은 하나의 작은 기능을 담당하며, 이들을 조합하여 원하는 파이프라인을 구성할 수 있습니다. Next.js 블로그를 구축할 때 이 글에서 소개한 플러그인들을 참고하여 자신만의 최적화된 MDX 처리 파이프라인을 만들어보시기 바랍니다.
참조자료
이 글을 작성하는데 참고한 주요 문서와 자료들입니다.
- Unified - Unified 생태계 공식 문서
- Next.js MDX - Next.js MDX 공식 가이드
- remark-plugins - remark 플러그인 목록
- rehype-plugins - rehype 플러그인 목록