Shiki와 함께하는 Markdown 코드 하이라이팅

설치 및 기본 사용법

Shiki는 다양한 테마와 언어에 대해 코드 하이라이팅을 제공하는 도구입니다. Markdown 파일을 HTML로 변환할 때 코드 블록에 서버사이드 하이라이팅을 적용하여 클라이언트 부담 없이 정확한 색상 출력을 얻을 수 있습니다.

설치

먼저, 프로젝트에 Shiki와 관련된 패키지를 설치합니다. 아래 명령어를 사용하여 @shikijs/rehype를 설치할 수 있습니다.

npm i -D @shikijs/rehype

사용법

Shiki를 사용하려면 unified와 함께 remarkrehype 시리즈의 플러그인을 사용하여 Markdown 파일을 처리하고, HTML로 변환합니다. 다음은 기본적인 사용 예제입니다.

import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype';
import rehypeStringify from 'rehype-stringify';
import rehypeShiki from '@shikijs/rehype';

const file = await unified()
	.use(remarkParse) // Markdown을 파싱
	.use(remarkRehype) // HTML로 변환
	.use(rehypeShiki, {
		// 단일 테마
		// theme: 'vitesse-light' // 단일 테마 사용

		// 다중 테마
		themes: {
			light: 'vitesse-light', // 라이트 테마
			dark: 'vitesse-dark' // 다크 테마
		}
	})
	.use(rehypeStringify) // HTML 문자열로 변환
	.process(await fs.readFile('./input.md')); // Markdown 파일을 읽고 처리

이 코드는 input.md라는 파일을 읽어와서, 해당 파일의 코드 블록에 Shiki를 사용해 라이트/다크 테마를 적용한 후, HTML로 변환합니다.

Shiki 인스턴스 관리

기본적으로 @shikijs/rehype의 기본 내보내기(default export)는 getSingletonHighlighter에서 공유되는 Shiki 인스턴스를 사용합니다. 이는 여러 프로세스에서 인스턴스가 지속됩니다. 그러나 Shiki 하이라이터의 수명 주기를 완전히 제어하고 싶다면, @shikijs/rehype/core의 세분화된 번들(Fine-grained Bundle)을 사용할 수 있습니다.

세분화된 번들 사용법

Shiki의 전체 번들 대신, 필요한 부분만 불러와 사용하고 싶다면 rehypeShikiFromHighlighter를 사용할 수 있습니다. 다음은 세분화된 번들을 사용하는 예제입니다.

import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype';
import rehypeStringify from 'rehype-stringify';
import rehypeShikiFromHighlighter from '@shikijs/rehype/core';

import { createHighlighterCore } from 'shiki/core';

const highlighter = await createHighlighterCore({
	themes: [
		import('shiki/themes/vitesse-light.mjs') // 라이트 테마
	],
	langs: [
		import('shiki/langs/javascript.mjs') // JavaScript 언어 하이라이팅
	],
	loadWasm: import('shiki/wasm') // WASM 파일 로드
});

const raw = await fs.readFile('./input.md');
const file = await unified()
	.use(remarkParse)
	.use(remarkRehype)
	.use(rehypeShikiFromHighlighter, highlighter, {
		themes: {
			light: 'vitesse-light',
			dark: 'vitesse-dark'
		}
	})
	.use(rehypeStringify)
	.processSync(raw); // 동기적으로 처리 가능

이 예제에서는 필요한 테마와 언어만 선택적으로 불러와서 사용할 수 있습니다. 이는 번들 크기를 줄이고, 더 나은 성능을 제공할 수 있습니다.

Created : 24. 08. 14. Modified : 26. 04. 13.
Designed by