Gatsby에 Syntax Highlighting 적용하기
Gatsby + MDX에서 syntax highlighting 적용 경험
Gatsby의 블로그를 운영하며 syntax highlighting이 필요하다고 느꼈다. 이전 글에서 자바스크립트 코드를 작성했는데 너무 눈에 들어오지 않았기 때문이다.
글에 앞서 내가 사용한 기술은 gatsby-plugin-mdx를 통해 mdx를 변환했다.
왜 나만 적용이 안될까
gatsby-remark-prismjs를 처음 적용해봤다. gatsby syntax highlighting라고 검색했을때 상단에 노출되는 플러그인이다.
공식문서를 따라 적용해봤지만 난 이상하게 적용이 안됐다. 확인해보니 하이라이팅할 코드가 토큰화 되어 있지 않았다.
이렇게 code태그 내부에 텍스트로 존재했다. gatsby-remark-prismjs의 문서에 토큰화에 관련된 부분이 없어 일단 다른 방법을 찾았다.
prism react renderer
이전과 비슷히 prismjs기반의 라이브러리였다.
공식문서에는 Prism을 통해 토큰화를 한다고 표시되어 있어 해당 라이브러리를 사용하기로 했다.
공식문서와 다른 블로그를 보며 따라해봤다.
$ npm install prism-react-renderer// or$ yarn add prism-react-renderer
CodeBlock 컴포넌트
import React from 'react';import Highlight, { defaultProps } from 'prism-react-renderer';import theme from 'prism-react-renderer/themes/github'; // 테마는 github 외에도 많다const CodeBlock = ({ children }) => {// 언어를 찾기위한 과정const className = children.props.className || '';const matches = className.match(/language-(?<lang>.*)/);const language = matches?.groups?.lang ?? '';return (<Highlight{...defaultProps}code={children.props.children.trim()}language={language}theme={theme}>{({ className, tokens, getLineProps, getTokenProps }) => (<pre className={className}>{tokens.map((line, i) => (<div {...getLineProps({ line, key: i })}>{line.map((token, key) => (<span {...getTokenProps({ token, key })} />))}</div>))}</pre>)}</Highlight>);};export default CodeBlock;
코드에서 볼 수 있듯 토큰화 하는 부분이 존재한다. pre태그 내부의 TextNode를 div와 span으로 토큰화를 시켜준다.
공식문서와 비슷하지만 다른 부분이 2가지 정도 있다.
code
Highlight컴포넌트의 props로 code를 넘긴다. 이때 우리가 넘겨줘야할 부분은 pre > code의 텍스트 값이다.
<pre><code>// 실제 적용될 코드</code></pre>
children.props.children은 실제 코드 부분 즉 code 내부의 텍스트 노드를 가져오기 위함이다.
language
보통 마크다운에서 언어를 표시하게 되면 language-javascript와 같이 language-라는 prefix가 붙게 된다.
예시의 javascript처럼 언어 부분을 파싱하기 위한 과정이 추가됐다.
style
{({ className, style, tokens, getLineProps, getTokenProps }) => (<pre className={className} style={style}>// ...</pre>);}
공식문서에서 style을 pre태그의 props로 내려주는데 이 부분을 제외했다.
style을 내려주면 pre태그의 background color가 변하는데 직접 설정한 색상을 적용하고 싶었다.
MDX 적용
기존의 pre태그를 CodeBlock 컴포넌트로 대체한다. MDXProvider를 사용한다.
<MDXProvidercomponents={{pre: CodeBlock,}}><MDXRenderer>{body}</MDXRenderer></MDXProvider>
기존 MDXRenderer컴포넌트를 MDXProvider로 감싸고 components props를 넘겨준다.
라이브러리가 적용 되어 토큰화 되고 github 테마로 하이라이팅도 된다.
gatsby syntax highlighting에 관련해 한글로 잘 정리된 블로그가 없어 직접 정리해봤다. 적용에 목적을 두어 prism-react-renderer라이브러리의 원리나 정확한 동작을 파악하진 못했다.