ReactMarkdown에 SyntaxHighlighter 사용하기

Rieul·2022년 10월 16일
2

Next.js & TypeScript 환경에서 ReactMarkdownSyntaxHighlighter를 공식 예제대로 따라 사용했는데 에러가 발생했습니다. 에러를 해결한 방법을 정리하려고 작성한 글입니다.

설치

ReactMarkdown & SyntaxHighlighter

yarn add react-markdown react-syntax-highlighter @types/react-syntax-highlighter

사용 예제 코드

이 코드는 github react-markdown에 나와있는 예제에 Next.js & TypeScript 환경에서 발생한 에러를 수정한 코드입니다.

import React from 'react'
import ReactDom from 'react-dom'
import ReactMarkdown from 'react-markdown'
import { PrismLight as SyntaxHighlighter } from 'react-syntax-highlighter';
import dracula from 'react-syntax-highlighter/dist/cjs/styles/prism/dracula';

// markdown
const markdown = `
	Here is some JavaScript code:
	```js
	console.log('Hello world!');
	```
	`;

ReactDom.render(
  <ReactMarkdown
    components={{
      code({node, inline, className, style, children, ...props}) {
        const match = /language-(\w+)/.exec(className || '')
        return !inline && match ? (
          <SyntaxHighlighter
            style={dracula}
            language={match[1]}
            PreTag="div"
            {...props}
          >{String(children).replace(/\n$/, '')}</SyntaxHighlighter>
        ) : (
          <code className={className} {...props}>
            {children}
          </code>
        )
      }
    }}
  >{markdown}</ReactMarkdown>,
  document.body
);

에러

1. SyntaxError: Unexpected token 'export'

에러 발생 상황

SyntaxHighlighter style 지정을 위해 dracula 모듈을 import 했을 때 발생

import dracula from 'react-syntax-highlighter/dist/esm/styles/prism/dracula';

에러 원인

react-syntax-highlighter 라이브러리에서는 esmcjs 두 가지 버전으로 스타일을 제공하는데, 프로젝트 모듈 시스템으로 ES Module을 사용하기 때문에 esm 버전 style 모듈을 사용했습니다.

이 프로젝트는 SSR 방식을 사용합니다.
Next.js는 빌드 때 Babel이 src 디렉토리에 es6 이상을 사용하는 코드를 es5 버전으로 변환합니다. 그래서 node_module에 있는 dracula 모듈은 변환되지 않습니다. Next.js는 SSR을 할 때 Node.js로 코드를 실행하는데, Node.js가 사용하는 CommonJS 모듈 시스템으로 변환되지 않은 dracula 모듈의 export 키워드를 실행하면서 에러가 발생한 것입니다.

해결 방법

Node.js가 사용하는 Common JS 모듈 시스템을 사용하는 cjs 버전 모듈을 사용해 해결했습니다.

import dracula from 'react-syntax-highlighter/dist/cjs/styles/prism/dracula';

2. The expected type comes from property 'style' which is declared here on type 'IntrinsicAttributes & IntrinsicClassAttributes & Readonly'

에러 발생 상황

SyntaxHighlighter style 지정을 위해 dracula 모듈을 SyntaxHighlighter style prop 값으로 설정 했을 때 발생

// code 생략 ...
<ReactMarkdown
    components={{
      code({node, inline, className, children, ...props}) { // CodeProps
        const match = /language-(\w+)/.exec(className || '')
        return !inline && match ? (
          <SyntaxHighlighter
            style={dracula} // SyntaxHighlighterProps
            language={match[1]}
            PreTag="div"
            {...props}
          >{String(children).replace(/\n$/, '')}</SyntaxHighlighter>
        ) : (
          <code className={className} {...props}>
            {children}
          </code>
        )
      }
    }} >{markdown}</ReactMarkdown>

에러 원인

CodeProps에 정의된 style타입과 SyntaxHighlighterProps에 정의된 style 타입이 달라서 오류가 발생했습니다.

// CodeProps
interface CodeProps {
	style?: React.CSSProperties | undefined;
	// ... 생략
}

// SyntaxHighlighterProps
interface SyntaxHighlighterProps {
	style?: { [key: string]: React.CSSProperties } | undefined;
    // ... 생략
}

해결 방법

  1. style 프로퍼티를 구조분해할당으로 사용하는 ...props에서 제외한다.
<ReactMarkdown
    components={{
                //	style parameter	추가			👇
      code({node, inline, className, children, style ...props}) { // CodeProps
        // ... 생략
  1. style 프로퍼티값을 ...props 뒤에 추가한다.
 <SyntaxHighlighter
			{...props}
            style={dracula} // ...props 뒤에 추가
            language={match[1]}
            PreTag="div"
          >{String(children).replace(/\n$/, '')}</SyntaxHighlighter>
profile
기록하는 습관

0개의 댓글