본문으로 건너뛰기

ADR-0015: 문서 본문 서식에 fumadocs 타이포그래피 프리셋과 shiki 를 쓴다

상태

Accepted

날짜

2026-08-12

맥락

문서 본문의 서식은 pages/docs 가 자체 CSS 140 줄로 정의하고 있었습니다. 마크다운이 만들어 내는 태그마다 규칙을 직접 작성한 것이며, 본 저장소가 문서 사이트를 목적으로 하는 이상 이 파일은 문서를 추가할 때마다 함께 자라는 구조였습니다.

두 가지 결함이 있었습니다.

코드 블록에 색이 없었습니다. 문서 34 개에 코드 블록 88 개가 있으며 그중 46 개가 TypeScript 입니다. 전부 단색으로 표시되어 예제의 구조를 눈으로 구분할 수 없었습니다.

Mermaid 다이어그램 2 개가 렌더링되지 않았습니다. 변환 파이프라인이 Mermaid 를 처리하지 않으므로 코드 원문이 그대로 노출되고 있었습니다.

문서 렌더링 영역의 시각적 기준으로 fumadocs 를 참조 대상으로 삼기로 했습니다. 화면 컴포넌트는 기존 디자인 시스템을 그대로 따르며, 마크다운이 렌더링되는 영역에 한해 별도 기준을 적용합니다.

결정

타이포그래피 프리셋을 외부에서 가져옵니다

@fumadocs/tailwind 의 typography 프리셋을 채택합니다. 본체인 fumadocs-uinext: 16.xreact: ^19.2.0 을 요구하므로 사용할 수 없으나, 타이포그래피는 peerDependenciestailwindcss: ^4.0.0 하나뿐인 별도 패키지로 분리되어 있습니다.

프리셋은 prose 유틸리티 하나를 생성하며 모든 규칙이 그 클래스의 하위 선택자로 중첩됩니다. Tailwind 4.1.12 로 실제 생성한 CSS 를 검사한 결과는 다음과 같습니다.

검사 항목 결과
전역 요소 선택자 없습니다. 추가분 전체가 @layer utilities.prose 블록 안에 있습니다
등록 방식 addComponentsaddVariant 만 사용하며 addBase 를 호출하지 않습니다
theme 확장 없습니다. 기존 유틸리티와 Spartan 토큰을 덮어쓰지 않습니다
추가 variant prose- 접두사가 붙은 것뿐입니다

색은 프리셋이 참조하는 --color-fd-* 여섯 개를 우리 토큰에 연결해 공급합니다. 별칭은 :root 가 아니라 .doc-body 선택자 안에 둡니다. 문서 본문 밖에서 이 계보가 존재하지 않게 하여 다른 코드가 실수로 참조하는 경로를 막기 위함입니다.

코드 블록은 빌드 시점에 색을 입힙니다

build-docs.mjs 가 shiki 로 하이라이팅합니다. 런타임에는 하이라이터가 실행되지 않으므로 애플리케이션 번들이 늘지 않습니다.

항목 선택 사유
테마 github-lightgithub-dark 를 함께 심음 화면에서 light-dark() 로 고르므로 토큰과 같은 방식으로 전환됩니다
배경 테마 제안값 대신 --muted 코드 블록 테두리와 배경이 문서의 다른 요소와 같은 계보를 씁니다
미등록 언어 평문으로 처리 언어 태그 오타로 빌드가 실패하지 않습니다

프리셋은 인라인 code 에 테두리와 배경을 넣지만 pre 는 다루지 않습니다. fumadocs 본체가 코드 블록을 React 컴포넌트로 처리하기 때문입니다. 따라서 코드 블록의 외형은 pages/docs 가 직접 정의하며, shiki 출력에 not-prose 클래스를 붙여 인라인 code 서식이 상속되지 않게 합니다.

다이어그램은 화면에서 그립니다

Mermaid 블록은 빌드 시점에 원본과 그릴 자리만 만들고, 브라우저가 mermaid 로 SVG 를 그립니다. 다이어그램이 있는 문서를 열 때만 mermaid 청크를 내려받습니다.

번들 비용을 실측한 결과는 다음과 같습니다. mermaid 11 은 다이어그램 종류별로 자체 지연 로드하므로 전량을 받지 않습니다.

범위 min gzip
전체 3,454kB 943kB
flowchart 렌더 경로 24 개 청크 711kB 185kB
진입 청크 28kB 11kB

테마는 mermaid 가 SVG 안에 색을 구워 넣으므로 CSS 로 전환할 수 없습니다. 루트의 color-scheme 을 관찰해 모드가 바뀌면 다시 그립니다.

securityLevel 은 mermaid 기본값인 strict 를 유지합니다. 내장 dompurify 가 스크립트와 이벤트 핸들러를 제거합니다. 런타임 DOM 주입 경로가 하나 생기므로 조건은 ADR-0013 의 개정 절에 기록했습니다.

검토한 대안

자체 CSS 를 계속 확장

구분 내용
장점 의존성이 늘지 않습니다. 모든 규칙이 저장소 안에 있어 수정 경로가 짧습니다
단점 서식 완성도가 작성자의 타이포그래피 판단에 묶입니다. 표·인용구·목록의 세부를 직접 조율해야 합니다
기각 사유 본 저장소의 목적은 표준 문서의 집필이며 타이포그래피 설계가 아닙니다. 검증된 결과물을 가져오는 편이 목적에 부합합니다

MDX 도입

구분 내용
장점 문서 안에서 컴포넌트를 직접 호출할 수 있어 Tabs · Steps 같은 요소를 쓸 수 있습니다
단점 MDX 는 JSX 를 React 컴포넌트 호출로 컴파일합니다. Angular 에는 대응 런타임이 없어 AST 를 Angular 컴포넌트로 매핑하는 렌더러를 직접 작성해야 합니다
기각 사유 문서 5,110 줄 중 표가 1,280 줄(25%)이고 이미지는 0 개입니다. 문서 규격이 인용 블록을 절당 1 개로 제한하므로 추가 컴포넌트 수요가 구조적으로 낮습니다. 파이프라인을 전면 교체할 근거가 되지 않습니다

fumadocs-ui 전체 채택

구분 내용
장점 Callout · Tabs · 검색 · 사이드바를 완성된 상태로 받습니다
단점 next: 16.xreact: ^19.2.0 을 요구합니다
기각 사유 Angular 프로젝트에 설치할 수 없습니다

다이어그램을 표로 대체하고 Mermaid 를 쓰지 않음

구분 내용
장점 의존성이 늘지 않고 프리렌더 산출물에 내용이 전부 담깁니다
단점 요소 간 관계를 표로 옮기면 연결의 전체 형태를 한눈에 볼 수 없습니다
기각 사유 처음 판단의 근거였던 "대상이 2 개뿐"이라는 수치가 수요를 나타내지 않았습니다. 변환 파이프라인이 Mermaid 를 처리한 적이 없어 그 2 개도 원문이 노출된 상태였으므로, 쓰지 않은 것이 아니라 쓸 수 없었던 것입니다. 문서 규격이 다이어그램에 범례를 붙이도록 규정하는 이상 수단을 없애는 것은 규격을 구현에 맞추는 일이 됩니다

Mermaid 빌드 시점 SVG 생성

구분 내용
장점 프리렌더 산출물에 다이어그램이 포함되어 레이아웃이 늘어나지 않습니다. 열람 시 추가로 받는 것이 SVG 뿐입니다
단점 @mermaid-js/mermaid-cli 가 puppeteer 를 필수 peer 로 요구합니다. 생성된 SVG 를 커밋해야 하며 다크 모드용 색을 따로 빼내야 합니다
기각 사유 생성물 비커밋 정책에 예외를 만들고 Chromium 을 의존성에 들이는 대가가, 열람 시 185kB 를 받는 비용보다 큽니다. 원본이 마크다운 안에 텍스트로 남는 편이 차이로 읽힙니다

결과

pages/docs 의 자체 CSS 가 140 줄에서 87 줄로 줄었고, 그중 30 줄은 라이선스 고지입니다. 실질 규칙은 여섯 개이며 전부 프리셋이 다루지 않는 영역입니다. 앵커 스크롤 여백, 표 가로 스크롤 래퍼, 코드 블록 외형, 토큰 별칭입니다.

감수하는 사항은 다음과 같습니다.

  • 전역 스타일이 커집니다. 산출물 CSS 가 95.7kB 에서 107.2kB 로 11.5kB(12.0%) 늘었습니다.
  • 생성 문서가 커집니다. shiki 가 토큰마다 두 테마의 색을 인라인 스타일로 심으므로 생성물이 497kB 에서 618kB 로 24.3% 늘었습니다. 문서 본문은 경로별 지연 청크이므로 첫 진입 비용에는 포함되지 않습니다.
  • 서식의 원본이 저장소 밖에 있습니다. 표나 목록의 세부를 바꾸려면 프리셋 위에 덮어쓰는 규칙을 추가해야 하며, 프리셋 갱신 시 그 덮어쓰기가 어긋날 수 있습니다.
  • 다이어그램이 프리렌더 산출물에 없습니다. 첫 표시 이후에 그려지므로 그 지점부터 본문이 아래로 밀립니다. 이동을 감추는 대신 높이를 0 에서 실제 값까지 전환해 보여줍니다. 예상 높이를 예약하지 않는 이유는 다이어그램마다 종횡비가 달라 예약값이 어긋나면 접혔다 펴지는 움직임이 되기 때문입니다.
  • 다이어그램이 있는 문서는 열람 시 185kB(gzip)를 더 받습니다. 초기 번들에는 포함되지 않으며 다이어그램이 없는 문서는 이 청크를 받지 않습니다.
  • mermaid 의 CommonJS 의존성 8 개를 angular.jsonallowedCommonJsDependencies 에 등록했습니다. 등록하지 않으면 빌드마다 경고가 8 줄 출력되어 실제 경고를 가립니다. 목록은 gantt 와 architecture 다이어그램이 쓰는 것들이며 flowchart 경로에서는 로드되지 않습니다.

프리셋은 MIT 라이선스(Copyright (c) 2023 Fuma)로 배포되며, 저작권 고지 전문을 pages/docs 의 CSS 상단에 유지합니다.

© 2026 dev.goraebap