본문 바로가기
개발일지/github

Github pages 블로그에 Markdown 내용 불러오기

by 한삐 2023. 3. 15.
728x90

필요한 패키지

yarn add gray-matter # 문자열이나 파일에서 머리말을 구문 분석, 파일에서 메타데이터와 내용 등 추출 시 사용
yarn add marked 
yarn add @types/marked # 타입스크립트의 경우
yarn add react-markdown # <div dangerouslySetInnerHTML={createMarkup()} />과 유사함
yarn add remark-gfm # 마크다운 문법이 다양하게 적용될 수 있도록 도와주는 플러그인
yarn add react-syntax-highlighter
yarn add @types/react-syntax-highlighter # 타입스크립트의 경우

참조
https://yarnpkg.com/package/react-markdown
https://yarnpkg.com/package/react-syntax-highlighter

 

- posting 파일들은 src 파일 안에 있다고 가정 -

 

// [slug].tsx 파일 생성
import { GetStaticPaths, GetStaticProps } from "next";
import { join } from "path";
import fs from "fs/promises";
import matter from "gray-matter";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
// import { darcula } from "react-syntax-highlighter/dist/esm/styles/prism"; - 에러 발생
import { dark } from "react-syntax-highlighter/dist/cjs/styles/prism";
import { vsDark } from "react-syntax-highlighter/dist/cjs/styles/prism";
import { darcula } from "react-syntax-highlighter/dist/cjs/styles/prism";


interface Props {
  title: string;
  date: string;
  content: string;
}

export default function BlogPost({ title, date, content }: Props) {
  return (
    <div>
      <h1>{title}</h1>
      <p>{date}</p>
      <ReactMarkdown
          className="markdown"
          remarkPlugins={[remarkGfm]}
          components={{
            code({ inline, className, children, ...props }) {
              const match = /language-(\w+)/.exec(className || "");
              return !inline && match ? (
                <SyntaxHighlighter
                  language={match[1]}
                  PreTag="pre"
                  {...props}
                  // style={dark}
                  style={darcula}
                  // style={vsDark}
                >
                  {String(children).replace(/\n$/, "")}
                </SyntaxHighlighter>
              ) : (
                <code className={className} {...props}>
                  {children}
                </code>
              );
            },
          }}
        >
          {content}
        </ReactMarkdown>
    </div>
  );
}

// 파일명을 통해 url 생성
export const getStaticPaths: GetStaticPaths = async () => {
  const postsDirectory = join(process.cwd() + "src" + "/posting", "blog");
  const filenames = await fs.readdir(postsDirectory);
  const paths = filenames.map(filename => ({
    params: { slug: filename.replace(/\.md$/, "") },
  }));
  return { paths, fallback: false };
};

// url에 해당하는 파일명을 찾아 matter로 데이터 추출
export const getStaticProps: GetStaticProps<Props> = async ({ params }) => {
  const slug = params?.slug as string;
  const filePath = join(process.cwd() + "src" + "/posting", "blog", `${slug}.md`);
  const fileContents = await fs.readFile(filePath, "utf8");
  const { data, content } = matter(fileContents);
  return {
    props: {
      title: data.title,
      date: data.date,
      content,
    },
  };
};

SyntaxHighlighter 내부의 style을 이용하기 위해서는 그에 맞는 소스를 가져와야 한다.

 

에러가 발생하는 ...dist/esm/styles/prism

import { darcula } from "react-syntax-highlighter/dist/esm/styles/prism";

 

 

에러가 발생하지 않는 imports

import { darcula } from "react-syntax-highlighter/dist/cjs/styles/prism";


import { dark } from "react-syntax-highlighter/dist/cjs/styles/prism";

 


import { vsDark } from "react-syntax-highlighter/dist/cjs/styles/prism";

 

스타일 등은 <ReactMarkdown />의 className을 통해 수정해줄 수 있다.

 

 

markdown 파일 생성 

// 파일명 : first-post.md
---
title: First-Post
date: "2023-02-28" <- 숫자만 사용하면 newDate()처럼 생성되어 타입 오류 발생 가능
---

# Deploy and test

holollollo

```javascript
const fn = () => {
	return "hi"
}
```

파일 생성 후 해당 링크 접속 시 정상적으로 접속 가능해진다.

ex. localhost:3000/first-post

 

url은 [slug].tsx 파일이 위치한 경로에 따라 달라질 수 있다. (nextjs 라우팅 방식)

 

728x90

댓글