2025. 03

CSS로 커스텀하는 마크다운 렌더러 만들기

마크다운 렌더러 with react

https://github.com/frfla/react-md-renderer/pkgs/npm/react-md-renderer

stable:

npm install @frfla/react-md-renderer@0.11.0

yarn add @frfla/react-md-renderer@0.11.0

마크다운? 어차피 CSS만 커스텀하면 될 일이 아닌가

노션 블로그를 만들면서 마크다운의 한계를 체감하고, 마크다운을 AST로 파싱하는 파서를 직접 만드는 게 아니라면 (다른 파서를 이용해야 한다면) 그 과정을 한 번 더 단축시켜주는 라이브러리를 만드는 것도 괜찮은 일이라고 생각했습니다. 실제로 react markdown같은 라이브러리를 이용해 보면서, 컴포넌트를 등록하는 일과 remark, rehype같은 플러그인을 등록해 사용하는 일은 꽤나 성가신 일이었습니다. 마크다운을 파싱해 컴포넌트로 렌더링할 일이 많이 발생하는 게 아니기 때문에 더더욱이요. 어차피 한계가 명확한 것이고, 간단히 사용만 해야 하는 상황이라면 이런 게 하나쯤 있어도 괜찮지 않을까 하는 생각도 해 보았습니다.

이왕 만드는 것, 스타일링 도구에 의존하지 않도록…

a, blockquote, checkbox, code, inlinecode, h1-h6, hr, img, li, ol, ul, p, table, strike, strong, italic

위의 마크업들에 대해 CSS를 커스텀할 수 있도록 하되, 스타일링 도구에 의존하지 않도록 하기 위해 API 설계를 고심해야 했습니다. 주요 스타일링 도구들의 작성 결과물은 다음과 같은데요,

  • 일반 style prop: object

  • 일반 className prop: string

  • vanilla extract: className={스타일 변수 할당(string)}

  • emotion, stitches: css prop: object or () => object

위의 특징들을 모두 포괄하기 위한 작업을 했습니다. 그래서 최종적인 API는 아래와 같은데요…

Typescript
<Renderer markdown={...}
	CSS={
		h1: ...,
		code: { fontSize: '0.75rem' },
		p: 'paragraph'
	classNamePrefix='abcd'
} />

위와 같이 ... 부분에 string, object, ()=>object 를 다 넣을 수 있습니다. 내부적으로 스타일을 잘 변환해서 삽입합니다. (내부 스타일링 라이브러리는 stitches를 사용합니다)

또, classNamePrefix prop으로 원하는 접두사를 사용할 수 있습니다. css classname 컨벤션이나 캐시 문제 등으로 해시값을 사용할 때 사용할 수 있습니다.

마무리

확장판인 MDX도 있고 더 좋은 게 많긴 하지만, 어쨌든 간단하게 마크다운만 딱 렌더링하는 상황일 때 사용하면 더없이 좋다고 생각합니다. 간단한 문서 페이지같은 것들을 만들 때 저도 잘 사용하고 있습니다. 필요한 건(이미 좋은 게 나와 있어도, 아직은 연습하는 차원에서) 직접 만들어서 쓰자는 주의이기도 하고, CSS 라이브러리 종속성에 대해 고민하느라 만들어 보게 된 패키지였습니다.

stable:

npm install @frfla/react-md-renderer@0.11.0

yarn add @frfla/react-md-renderer@0.11.0