Next.js
&TypeScript
환경에서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
라이브러리에서는 esm
과 cjs
두 가지 버전으로 스타일을 제공하는데, 프로젝트 모듈 시스템으로 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;
// ... 생략
}
style
프로퍼티를 구조분해할당으로 사용하는 ...props
에서 제외한다.<ReactMarkdown
components={{
// style parameter 추가 👇
code({node, inline, className, children, style ...props}) { // CodeProps
// ... 생략
style
프로퍼티값을 ...props
뒤에 추가한다. <SyntaxHighlighter
{...props}
style={dracula} // ...props 뒤에 추가
language={match[1]}
PreTag="div"
>{String(children).replace(/\n$/, '')}</SyntaxHighlighter>