DogKaeBi

[Next.js] 마크다운 종합편

fetch > gray-matter > markdown-to-jsx > typography > prism.js 의 순서로 일기 내용을 완성했다.

[Next.js] 마크다운 종합편

서론

이전 편

[마크다운 불려오기 fetch]
[마크다운 파싱 markdown-to-jsx]
[마크다운 디자인 typography]
[마크다운 코드 강조 prism.js]
[마크다운 프론트매터 gray-matter]


계획 & 실행

계획...

  • 다이나믹 라우팅 페이지 post에서 slug에 따라서 다른 내용 출력
  • 일기 내용은 문자열이면 되지만 markdown이 제일 편리해서 사용

실행...

  • front matter의 파싱은 gray-matter 사용
  • 글 내용 jsx로 parsing을 markdown-to-jsx 사용
  • css는 tailwind의 typography 사용
  • syntax highlight는 prism.js 사용


임시 Markdown

파싱된 결과를 보기 위해서 각각 테스트 내용만 작성

---
title: "제목 test 1"
slug: "test1"
date: 2024-01-01 23:59:59
---

# h1 타이틀

This is a test blog texture.....

## h2 타이틀

*기울기*

**강조**

[링크](https://github.com/)

[로고 이미지](/logo.png)

```jsx
const num = 1;
return <h1>h1 제목</h1>
```


gray-matter

npm 사이트 : https://www.npmjs.com/package/gray-matter

Markdown 파일을 객체로 파싱하는 라이브러리.
front matter는 key이름 data.
글 내용은 key이름 content.


gray-matter 설치

터미널에서 npm 사용 설치

npm install gray-matter

gray-matter 사용법

함수 불려오기

import matter from "gray-matter";

함수 사용하기

const grayMatter = matter(markdownData);
const frontMatter = grayMatter.data;
const content = grayMatter.content;


markdown-to-jsx

npm 사이트 : https://www.npmjs.com/package/markdown-to-jsx

Markdown 형식의 텍스트(문자열)을 jsx로 파싱하는 라이브러리이다.
Markdown 컴포넌트로 사용된다.


markdown-to-jsx 설치

터미널에서 npm 사용 설치

npm i markdown-to-jsx

markdown-to-jsx 사용법

import Markdown from "markdown-to-jsx";

return <Markdown># 제목 h1</Markdown>;

Markdown 컴포넌트 import.
컴포넌트를 사용하고 자녀로 md 텍스트를 작성.



Typography

tailwind 설명문 : https://tailwindcss.com/docs/plugins#typography
공식 github : https://github.com/tailwindlabs/tailwindcss-typography

기본 html 디자인 css를 제공하는 plugin이다.


Typography 설치

터미널에서 npm 사용 설치

npm install -D @tailwindcss/typography

Typography 설정

tailwind.config.js 파일에 설정 추가

/** @type {import('tailwindcss').Config} */
module.exports = {
  theme: {
    // ...
  },
  plugins: [
    require("@tailwindcss/typography"),
    // ...
  ],
};

Typography 사용법

사용할 태그의 class명을 prose으로 한다.

<article class="prose">
  <h1>제목</h1>
  <p>내용 테스트</p>
</article>

Typography 기본 설정

크기 변경 prose-크기 (prose-sm)
회색 변경 prose-색상 (prose-slate)

등의 방식으로 기본 설정 가능


Typography 디자인 변경

prose-태그명:tailwindCss 의 방식으로 디자인 변경 가능
(prose-strong:text-green-600)



prism.js

공식 사이트 : https://prismjs.com/

syntax highlighter
문법 강조 라이브러리


prism 설치

터미널에서 npm 사용 설치

npm i prismjs

prism 사용법

가져오기

import Prism from "prismjs"; // front
// or
const Prism = require("prismjs"); // backend

함수 사용하기

const html = Prism.highlight(mdPreCodeTagContent, Prism.languages.javascript, "javascript");

기본 사용법이지만...

나는 편리를 위해...
컴포넌트 작성.
highlightAll()을 사용.
사용할 페이지에서 컴포넌트 사용.


PrismLoader 컴포넌트

pre code 태그의 코드의 문법 강조를 위한 컴포넌트 작성

// .\app\components\PrismLoader.js

"use client";
import { useEffect } from "react";

import Prism from "prismjs";
import "prismjs/themes/prism-okaidia.css";
import "prismjs/components/prism-jsx";
import "prismjs/components/prism-bash";
import "prismjs/components/prism-git";
import "prismjs/components/prism-markdown";

export default function PrismLoader() {
  useEffect(() => {
    Prism.highlightAll();
  }, []);
  return <div className="hidden" />;
}
  • theme(테마) 선택 (공식 사이트에서 확인)
  • 강조하고 싶은 언어 추가로 가져오기
  • useEffect 사용
  • Prism.highlightAll()으로 모든 코드 강조
  • return 값 숨김


Post 페이지

slug 확인 md파일 가져와서 파싱하기

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

import matter from "gray-matter";
import Markdown from "markdown-to-jsx";
import PrismLoader from "../../../components/PrismLoader";

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

  const options = {
    overrides: {
      img: ({ src, alt, ...props }) => <Image width={500} height={500} alt={alt} src={src} {...props} />,
    },
  };
  const mdClass = "prose prose-stone prose-strong:text-green-600";

  return (
    <>
      <PrismLoader />
      <h1>{frontMatter.title}</h1>
      <p>{frontMatter.date}</p>
      <Markdown className={mdClass} options={options}>
        {content}
      </Markdown>;
    </>
  );
}

next.js에서 fetch는 경로 전체를 사용해야 한다.
상대경로를 사용하고 싶으면 http 기능이나 환경변수를 사용할 수 있지만 여기서는 자세히 설명하지 않겠다.

상단 5개 const 변수 :

  • props.params.slug과 같은 이름의 md 파일을 fetch
  • 받은 내용을 text()으로 문자열로 변경
  • gray-matter의 matter()함수로 파싱

Markdown 컴포넌트 준비 :

  • options와 mdClass 준비
  • options사용. img 태그 Image 컴포넌트로 변경

return 값 :

  • 코드 강조 prism.js 사용 : PrismLoader 컴포넌트 별도 작성
  • 파싱된 front matter의 제목 및 작성시간 출력
  • Markdown 컴포넌트 사용. 파싱된 content 사용


경과와 결과

markdown 읽기

  • md 파일명과 slug명을 동일하게 했다.
  • fetch로 파일 읽기
  • text()함수로 파일 -> 텍스트로 파싱

front matter 객체

  • gray-matter 설치
  • matter()함수로 텍스트 -> 객체로 파싱

Markdown 컴포넌트

  • markdown-to-jsx 설치
  • Markdown 컴포넌트 사용. 객체.content -> jsx(html)로 파싱

css 디자인

  • Typography 설치.
  • tailwind설정 추가
  • 사용 : Markdown의 class명 "prose"

code 문법 강조

  • prism.js 설치
  • PrismLoader 컴포넌트 생성. 공백 요소 return
  • Prism.highlightAll()을 useEffect로 사용
  • Markdown 컴포넌트 사용하는 페이지에서 PrismLoader 사용


원하는 결과는 잘 얻었다.