하나의 .mdx파일에서 Mermaid 2개 사용시 렌더링 오류
Nextra에서 하나의 .mdx파일에서 Mermaid 다이어그램을 2개 사용했을 때 마지막 하나만 출력되는 오류가 발생
※ Mermaid란?
2023.06.20 - [문서 정리 프레임워크/Nextra] - [Nextra] FileTree, Steps, Mermaid사용
[Nextra] FileTree, Steps, Mermaid사용
Nextra에서 FileTree, Steps, Mermaid사용FileTree 컴포넌트의 사용방법import { FileTree } from "nextra-theme-docs"; 출력결과Steps 컴포넌트의 사용방법import { Steps } from "nextra-theme-docs"; ### Step1Step1의 내용이다.### Step2
kfdd6630.tistory.com
문제가 발생하는 이유
1. 이 문제는 Nextra에서 Mermaid 다이어그램이 여러 개 연속해서 선언될 때 발생하는 렌더링 충돌 때문에 발생
2. Mermaid의 SSR 렌더링 타이밍과 Nextra의 마크다운 처리 방식이 충돌하면서 첫 번째 mermaid 블록이 무시되고 마지막 블록만 렌더링되는 문제가 발생
해결 방법?
1. Mermaid 블록 사이에 공백 콘텐츠 <br /> 혹은 " "삽입
2. Mermaid를 <div>로 감싸 명시적으로 분리
3. Mermaid를 컴포넌트화하여 사용
결과
1. 일반적인 해결법인 마크다운 문단 구분, <br/>, <div>, 주석 삽입 모두 효과 없음
2. 3가지 모두 해결되지 않음
이유는?
1. Nextra + rehype + mermaid 플러그인의 구조적인 렌더링 버그
2. 현재 Nextra에서는 mermaid 코드 블록을 rehype-plugin이 단 한 번만 처리하기 때문에 두 번째 이후 코드블록만 DOM 상에서 실행되는 현상이 생기는 문제
3. Nextra의 Markdown → HTML 변환기(markdoc, remark, rehype 등) 혹은 Mermaid 플러그인에서 발생하는 렌더링 충돌이 발생
해결 방법
Nextra 공식팀과 커뮤니티에서 가장 권장하는 방식인 <Mermaid> 컴포넌트 사용하여 해결
1. mermaid 다운로드
# pnpm 사용
pnpm add mermaid
# npm 사용
npm install mermaid
2. mermaid 컴포넌트 생성(components/Mermaid.tsx)
'use client'
import { useEffect, useRef } from 'react'
import mermaid from 'mermaid'
mermaid.initialize({ startOnLoad: false })
export default function Mermaid({ chart }: { chart: string }) {
const ref = useRef<HTMLDivElement>(null)
useEffect(() => {
if (ref.current) {
mermaid.render('graph-div', chart).then(({ svg }) => {
ref.current!.innerHTML = svg
})
}
}, [chart])
return <div ref={ref} />
}
이렇게 사용한다면 Mermaid가 한 페이지에 두 개가 출력되지만 2가지 문제를 해결해야 함
1. 두 개의 Mermaid 다이어그램이 겹쳐 나오는 현상
2. Hydration Error 발생
1. 두 개의 Mermaid 다이어그램이 겹쳐 나오는 현상 해결
1의 이유는 mermaid.render('graph-div', ...) → 이 ID가 고정되어 있어 두 개가 같은 DOM 요소를 공유하여 발생
해결방법
1. nanoid라는 ID 중복 없이 랜덤 생성해주는 초경량 라이브러리 다운로드
# npm 사용
npm install nanoid
# pnpm 사용
pnpm add nanoid
2. nanoid 적용
'use client'
import { useEffect, useRef } from 'react'
import mermaid from 'mermaid'
import { nanoid } from 'nanoid'
mermaid.initialize({ startOnLoad: false })
export default function Mermaid({ chart }: { chart: string }) {
const renderRef = useRef<HTMLDivElement>(null)
const idRef = useRef(`mermaid-${nanoid()}`) // 고유 ID 부여
useEffect(() => {
if (!renderRef.current) return
const render = async () => {
try {
const { svg } = await mermaid.render(idRef.current, chart)
renderRef.current!.innerHTML = svg
} catch (e) {
console.error("Mermaid render error:", e)
}
}
render()
}, [chart])
return <div className="mermaid" ref={renderRef} />
}
2. Hydration Error 발생
React + Next.js(Nextra)에서 서버에서 렌더링된 HTML과 클라이언트에서 재렌더링된 UI가 다를 때 발생하는 오류
해결방법
Next.js에서 서버 렌더링을 완전히 끄고, 클라이언트에서만 렌더링되도록 해야 함
1. components/Mermaid.tsx
'use client'
import { useEffect, useRef } from 'react'
import mermaid from 'mermaid'
import { nanoid } from 'nanoid'
mermaid.initialize({ startOnLoad: false })
export default function Mermaid({ chart }: { chart: string }) {
const ref = useRef<HTMLDivElement>(null)
const id = useRef(`mermaid-${nanoid()}`)
useEffect(() => {
if (!ref.current) return
mermaid.render(id.current, chart).then(({ svg }) => {
ref.current!.innerHTML = svg
})
}, [chart])
return <div ref={ref} />
}
2. .mdx에서는 반드시 동적 import 사용(SSR 사용하지않음)
// components/ClientMermaid.tsx
import dynamic from 'next/dynamic'
const Mermaid = dynamic(() => import('./Mermaid'), { ssr: false })
export default Mermaid
3. .mdx 사용 예
import Mermaid from '@/components/ClientMermaid'
### 🗓 타임라인
<Mermaid chart={`timeline
title 마일스톤
2025-04-10 : 시작
2025-08-14 : 종료
`} />
---
### 🔁 흐름도
<Mermaid chart={`flowchart TD;
A --> B;
`} />
'문서 정리 프레임워크 > Nextra' 카테고리의 다른 글
[Nextra] Mermaid Gantt 차트 반응형 적용 (0) | 2025.04.10 |
---|---|
[Nextra] .gif 파일 unoptimized warning 해결 (0) | 2024.08.14 |
[Nextra] index 없애기 (0) | 2024.08.13 |
[Next.js, Nextra] video (0) | 2024.08.12 |
[Nextra] existSync is not a function (0) | 2024.08.11 |
댓글