TIL 5 분 소요
Mermaid 렌더링 안 되는 문제 — allowDangerousHtml 설정
mermaid remark rehype markdown troubleshooting
문제 발견
Supabase에서 가져온 블로그 게시글에 Mermaid 다이어그램을 추가했는데, 브라우저에서 렌더링되지 않았다. 데이터베이스에는 Mermaid 코드 블록이 정상적으로 저장되어 있었다.
```mermaid
flowchart LR
A[Start] --> B[Process]
B --> C[End]
```증상
Playwright로 페이지를 확인했을 때:
<pre class="mermaid">요소: 0개.mermaid-diagramdiv: 0개- 렌더링된 SVG: 0개
하지만 서버 로그에는 Mermaid 블록을 찾았다는 메시지가 출력되고 있었다:
[remarkMermaid] Found 3 mermaid blocks, isMdx: false원인 파악
remarkMermaid 플러그인은 Markdown의 Mermaid 코드 블록을 HTML로 변환한다. 비-MDX 모드에서는 다음과 같은 HTML 노드를 생성한다:
// src/lib/remark-mermaid.ts
const htmlNode = {
type: "html",
value: `<div class="mermaid-diagram my-6 flex justify-center">
<pre class="mermaid">${escapeHtml(code)}</pre>
</div>`,
};문제는 src/lib/markdown-processor.ts의 unified 파이프라인 설정이었다:
.use(remarkMermaid)
.use(remarkCallout)
.use(remarkRehype, { allowDangerousHtml: false }) // ❌ 여기가 문제
.use(rehypePrettyCode, {
// ...
})
.use(rehypeRaw)
.use(rehypeStringify)remarkRehype의 allowDangerousHtml 옵션이 false로 설정되어 있어서, remarkMermaid가 생성한 HTML 노드가 제거되고 있었다.
해결
allowDangerousHtml을 true로 변경했다:
.use(remarkMermaid)
.use(remarkCallout)
.use(remarkRehype, { allowDangerousHtml: true }) // ✅ 수정
.use(rehypePrettyCode, {
// ...
})
.use(rehypeRaw)
.use(rehypeStringify)작동 원리
- remarkMermaid: Mermaid 코드 블록을 HTML 노드로 변환
- remarkRehype: Markdown AST를 HTML AST로 변환
allowDangerousHtml: true— HTML 노드를 보존
- rehypeRaw: 보존된 HTML 문자열을 파싱하여 실제 HTML 노드로 변환
- rehypePrettyCode: 코드 블록 문법 강조 (Mermaid HTML은 건드리지 않음)
- rehypeStringify: 최종 HTML 문자열 생성
검증
수정 후 Playwright로 확인:
{
mermaidPreElements: 3, // ✅
mermaidDiagramDivs: 3, // ✅
renderedSvgDiagrams: 3 // ✅
}클라이언트 사이드 mermaid.js가 <pre class="mermaid"> 요소를 찾아서 인터랙티브 SVG 다이어그램으로 변환했다.
배운 점
remarkRehype의 allowDangerousHtml
allowDangerousHtml 옵션은 이름이 위험해 보이지만, remark 플러그인이 생성한 HTML을 보존하는 데 필요하다.
false(기본값): HTML 노드를 제거 — XSS 공격 방지true: HTML 노드를 보존 — 커스텀 플러그인의 HTML 출력 허용
rehypeRaw의 역할
rehypeRaw는 allowDangerousHtml: true와 함께 사용된다:
remarkRehype가 HTML 문자열을 보존rehypeRaw가 HTML 문자열을 실제 HTML AST 노드로 파싱
rehypeRaw 없이 allowDangerousHtml: true만 설정하면, HTML이 문자열로만 남아서 제대로 렌더링되지 않는다.