[Gatsby] with MDX

찐새·2022년 12월 3일
0

Gatsby

목록 보기
3/6
post-thumbnail

MDX는 마크다운에서 컴포넌트(jsx, tsx 등)를 허용하는 확장자다.

install

  • Gatsby에서 mdx 파일을 쿼리로 사용하는데 필요한 플러그인을 설치한다.
  • npm install gatsby-plugin-mdx gatsby-source-filesystem @mdx-js/react
  • 설치 후 config 파일에 gatsby-plugin-mdx를 추가한다.
import type { GatsbyConfig } from "gatsby";

const config: GatsbyConfig = {
  // (...)
  plugins: [
    `gatsby-plugin-mdx`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        path: `${__dirname}/blog-posts`,
      },
    },
  ],
};

export default config;

usage

  • 예시로 hello.mdx 파일을 생성 후 frontmatter를 포함한 내용을 작성했다.

frontmatter는 마크다운 파일의 메타데이터를 식별하는 방법으로, 3개짜리 하이픈(-) 사이에 식별 내용을 적는다.
ex

<!-- frontmatter -->
---
title: Bla Bla
---
---
title: Hello everyone
category: personal
date: "2022-12-03"
author: JS
slug: hello-everyone
---

# Hello everyone!

Welcome to my blog post. I'm very happy to have you all here with me on this special occasion.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi consectetur magna vitae lorem posuere, ut bibendum metus condimentum. Nullam lacinia, sapien ac congue fermentum, metus dolor blandit sem, in volutpat turpis nisi ut enim. Suspendisse dignissim risus a faucibus commodo. Pellentesque pulvinar lobortis pretium. Nullam ut justo a nulla pellentesque lobortis a id quam. Vestibulum scelerisque molestie lectus, et tincidunt neque malesuada vel. Morbi turpis massa, dignissim sed libero eu, finibus laoreet eros. Aenean mi nisl, posuere ac magna quis, volutpat ultricies nisi. In id ligula vitae nibh scelerisque imperdiet. Nulla tempor eleifend elementum. Nunc at arcu at massa finibus viverra ac hendrerit quam.
  • Gatsby가 제공하는 GraphQL ExplorerallMdx가 생기고, 파일의 각종 정보를 찾을 수 있다.

GraphQL allMdx

date 포맷 변경

  • date의 옵션 중 formatString으로 포맷을 변경한다.
# GrapQL
query MyQuery {
  allMdx {
    nodes {
      frontmatter {
        date(formatString: "MM.DD, YYYY")
      }
    }
  }
}

# JSON
{
  "data": {
    "allMdx": {
      "nodes": [
        {
          "frontmatter": {
            "date": "12.03, 2022"
          }
        },
        {
          "frontmatter": {
            "date": "12.03, 2022"
          }
        }
      ]
    }
  },
  "extensions": {}
}

excerpt

  • 긴 길이의 데이터를 축약해준다. pruneLength로 노출 길이를 조절할 수 있다.
# GraphQL
query MyQuery {
  allMdx {
    nodes {
      excerpt(pruneLength: 30)
    }
  }
}

#JSON
{
  "data": {
    "allMdx": {
      "nodes": [
        {
          "excerpt": "Welcome to my blog post. I…"
        },
        {
          "excerpt": "See you later! Lorem ipsum…"
        }
      ]
    }
  },
  "extensions": {}
}

Query

  • 다른 쿼리와 마찬가지로 export const query = graphql로 해당 데이터를 받아온다.
const Blog = ({ data }: PageProps<Queries.BlogPostsQuery>) => {
  return (
    <Layout title="Blog">
      <section>
        {data.allMdx.nodes.map((file, idx) => (
          <article key={idx}>
            <Link to={`/blog/${file.frontmatter?.slug}`}>
              <h3>{file.frontmatter?.title}</h3>
              <h5>
                {file.frontmatter?.author} in: {file.frontmatter?.category}
              </h5>
              <h6>{file.frontmatter?.date}</h6>
              <hr />
              <p>{file.excerpt}</p>
            </Link>
          </article>
        ))}
      </section>
    </Layout>
  );
};

export default Blog;

export const query = graphql`
  query BlogPosts {
    allMdx {
      nodes {
        frontmatter {
          slug
          title
          date(formatString: "YYYY.MM.DD")
          category
          author
        }
        excerpt(pruneLength: 50)
        body
      }
    }
  }
`;
  • 앞서 작성한 frontmatter를 포함한 데이터를 받을 수 있다.

하위 페이지

  • Gatsby가 제공하는 다이나믹 라우트로 하위 페이지 이동이 가능하다.
  • 상위 페이지를 index로 하는 폴더를 생성하고, 중괄호({})로 감싼 이름을 가진 파일을 생성한다.
/blog
  ├─ index.tsx
  └─ {mdx.frontmatter__slug}.tsx
  • 예시로 frontmatter에 담긴 slug로 하위 경로를 설정했다.
    • 따라서 위 경로의 {mdx.frontmatter__slug}mdx 파일의 frontmatter 중 slug를 파일명으로 삼아라를 의미한다.
  • slug를 통해 가져온 데이터는 다음과 같다.

GraphQL mdx

  • 쿼리는 여러 파일을 각각의 slug로 검색하는 문법으로 작성한다.
// blog/{mdx.frontmatter__slug}.tsx

export default function BlogPost({ data, children }: PageProps<Queries.PostDetailQuery>) {
  return (
    <Layout title={`${data.mdx?.frontmatter?.title}`}>
      <div>{children}</div>
    </Layout>
  );
}

export const query = graphql`
  query PostDetail($frontmatter__slug: String) {
    mdx(frontmatter: { slug: { eq: $frontmatter__slug } }) {
      frontmatter {
        author
        category
        date
        slug
        title
      }
    }
  }
`;
  • 범용적으로 검색할 조건을 $ 문자와 합쳐 쿼리에 전달한다.
  • 내용은 따로 가져오거나 할 필요 없이 컴포넌트의 프로퍼티 중 children으로 mdxbody를 적용할 수 있다.
  • mdx 파일 내에 작성한 컴포넌트도 자동으로 파싱되어 출력된다.
// temp.tsx
import React from "react";

export default function Temp() {
  const [change, setChange] = React.useState(false);
  const onChangeClick = () => setChange((prev) => !prev);
  return (
    <div>
      <h3>{change ? "That" : "This"} Temp Page</h3>
      <button onClick={onChangeClick}>
        Change {change ? "That ➡ This" : "This ➡ That"}
      </button>
    </div>
  );
}
<!-- hello.mdx -->
---
title: Hello everyone
category: personal
date: "2022-12-03"
author: JS
slug: hello-everyone
---

import Temp from "../src/components/temp";

# Hello everyone!

<Temp />

⏫컴포넌트를 렌더링한 모습⏫

결과

Gatsby with MDX


참고
노마드코더 - 리액트JS 마스터 클래스
gatsby-plugin-mdx
MDX docs
What is Frontmatter?

profile
프론트엔드 개발자가 되고 싶다

0개의 댓글