DogKaeBi

[Next.js] 블로그 페이지. 마크다운 파싱

문자열로 받은 markdown 파일의 글을 jsx(html형식)으로 변경하기

[Next.js] 블로그 페이지. 마크다운 파싱

서론

[마크다운 불려오기]

// .\app\blog\[slug]\page.js

export default async function Post(props) {
  const slug = props.params.slug;
  const postRes = await fetch(`http://localhost:3000/${slug}.md`);
  const data = await test.text();

  return <>{data}</>;
}

전편에서는
slug와 같은 이름의 markdown 파일을
public 폴더에 만들었다.

하지만 출력된 내용은
문자열 그대로인 것으로 보인다.

이번에는 Markdown을 html형식으로 만들어 볼 생각이다.


md(markdown)을 파싱(parsing)하는 방법?도구?는 여러가지가 있다.
조금 유의해야 하는 점은
Next.js를 사용하고 있기 때문에
html으로 파싱하는 것이 아니라
js (jsx)으로 파싱해야 한다.

Next.js에서는 mdx를 많이 사용하는 것 같다.
Next.js 공식 MDX 사용 설명

나도 원래 MDX를 사용할까 많이 검색해봤지만...
그냥 md 파일을 사용하고 싶어서
다른 방법을 찾아봤다.

결국 사용한 것은 markdown-to-jsx,
<Markdown> 컴포넌트이다.



Markdown 컴포넌트

[npmjs 설명 안내문]

사용법이 간단하고,
현재 코드의 const data = await test.text();
data 변수를 그대로 사용할 수 있었다.


markdown-to-jsx 설치

npm i markdown-to-jsx

터미널에 명령어를 입력해서 설치.


Markdown 컴포넌트 사용

// .\app\blog\[slug]\page.js

import Markdown from "markdown-to-jsx";

export default async function Post(props) {
  const slug = props.params.slug;
  const postRes = await fetch(`http://localhost:3000/${slug}.md`);
  const data = await test.text();

  return <Markdown>{data}</Markdown>;
}

사용법은 아주 간단하다.
Markdown 컴포넌트를 불려오고
자녀로 markdown내용을 문자열로 사용한다.


간단히 예시로 설명하면

<Markdown># h1제목</Markdown>

위의 내용은 브라우저에서
아래의 html으로 파싱된다.

<article>
  <h1>h1 제목</h1>
</article>

img - Image 변경

테스트해보니
이미지가 제대로 나오지 않고 오류 경고도 나온다.

markdown-to-jsx에서 이미지는
기본적으로 img태그로 출력된다.
하지만
next.js에서는
img태그를 사용하지 말라고 경고한다.

next.js은 SSR으로
직접 외부 이미지를 사용하지 않는 것을 추천하는 것 같다.

그리고 직접 테스트한 결과.
이미지의 경로나 형식에 따라서
Image컴포넌트는 대부분 정상 표시되지만
img태그는 이미지가 깨지는 경우가 있다.

그래서 options 변수를 만들었다.

const options = {
  overrides: {
    img: ({ src, alt, ...props }) => <Image width={500} height={500} alt={alt} src={src} {...props} />,
  },
};

상세 설명과 사용법은
[npmjs 설명 안내문]에서 확인 가능하다.

간단히 설명하면...
원래 img 태그를 Image 컴포넌트로 대체하고,
img에 받았던 속성도 Image의 속성으로 지정했다.

추가로 Image 컴포넌트는 필수로 크기가 필요해서
임의로 width={500} height={500}으로 지정했다.

그리고
Markdown컴포넌트에 옵션을 추가했다.

// .\app\blog\[slug]\page.js

import Markdown from "markdown-to-jsx";

export default async function Post(props) {
  const slug = props.params.slug;
  const postRes = await fetch(`http://localhost:3000/${slug}.md`);
  const data = await test.text();
  const options = {
    overrides: {
      img: ({ src, alt, ...props }) => <Image width={500} height={500} alt={alt} src={src} {...props} />,
    },
  };

  return <Markdown options={options}>{data}</Markdown>;
}


결과

브라우저로 결과을 받을 때,
각 태그가 잘 만들어져서 표시된다.
하지만 아무런 디자인이 없다.

tailwind css를 사용했기 때문에
아무 스타일이 없는 상태이다.