List

gatsby create post

Part 2

이전 글에서 slug를 만들어지는 과정을 알아보았다. 이번 파트에서는 post가 어떻게 만들어지는지 확인해보자.

Create Post

gatsby-node.js

const { createFilePath } = require(`gatsby-source-filesystem`);
exports.onCreateNode = ({ node, getNode, actions }) => {
  const { createNodeField } = actions;
  if (node.internal.type === `MarkdownRemark`) {
    const slug = createFilePath({ node, getNode, basePath: `pages` });
    createNodeField({
      node,
      name: `slug`,
      value: slug,
    });
  }
};

exports.createPages = async ({ graphql, actions }) => {
  // **Note:** The graphql function call returns a Promise
  const result = await graphql(`
    query {
      allMarkdownRemark {
        edges {
          node {
            fields {
              slug
            }
          }
        }
      }
    }
  `);
  console.log(JSON.stringify(result, null, 4));
};

You’ve added an implementation of the createPages API which Gatsby calls so plugins can add pages. Gatsby가 page를 추가할 수 있는 createPages API를 위처럼 구현한 것이다.

graphQL 은 promise비동기 방식으로 호출되어진다. async-await를 써서 비동기로 동작하도록 하자.

promise / callback createPages를 비동기 방식 2개에 대해서 알아보고자 한다.

// Promise API
exports.createPages = () => {
  return new Promise((resolve, reject) => {
    // do async work
  });
};
// Callback API
exports.createPages = (_, pluginOptions, cb) => {
  // do Async work
  cb();
};

Gatsby에서 page를 만들 때는

  1. GraphQL에 data를 쿼리호출하고
  2. 그 결과를 page에 맵핑하는 것이다.

onCreateNode createPages 코드는 markdown파일을 제공된 graphQL함수를 통해 page를 만드는 첫번째 step 이다.

1

위와 같이 graphQL로 쿼리호출한 결과값을 볼 수 있다.

그리고 page를 만들려면 slug이외에 page에 들어가야할 template component이 필요하다. 그런면에서 React는 아주 강력하게 사용될 수 있다. page에 사용될 template component를 만들어보자.

src/templates 폴더에 {component}-template.js 파일을 만들어 관리한다. 예시로 src/templates/blog-post.js 파일을 만들어본다.

src/templates/blog-post.js

import React from "react";
import Layout from "../components/layout";
export default function BlogPost() {
  return (
    <Layout>
      <div>Hello blog post</div>
    </Layout>
  );
}

그리고 gatsby-node.js 파일에서 createPages 내용을 수정한다.

const path = require(`path`);

exports.createPages = async ({ graphql, actions }) => {
  const { createPage } = actions;
  const result = await graphql(`
    query {
      allMarkdownRemark {
        edges {
          node {
            fields {
              slug
            }
          }
        }
      }
    }
  `);
  result.data.allMarkdownRemark.edges.forEach(({ node }) => {
    createPage({
      path: node.fields.slug,
      component: path.resolve(`./src/templates/blog-post.js`),
      context: {
        // context에 전달 된 데이터는 페이지 쿼리에서 GraphQL 변수로 사용 가능하다.
        slug: node.fields.slug,
      },
    });
  });
};

createPage를 통해서 page가 생성된다.

2

실제로 page를 보여주기 위한 데이터들을 가져오는 것으로 template파일을 수정해보자.

src/templates/blog-post.js

import React from "react";
// graph ql import
import Layout from "../components/layout";

export default function BlogPost({ data }) {
  const post = data.markdownRemark;
  return (
    <Layout>
      <div>
        <h1>{post.frontmatter.title}</h1>
        <div dangerouslySetInnerHTML={{ __html: post.html }} />
      </div>
    </Layout>
  );
}
export const query = graphql`
  query($slug: String!) {
    markdownRemark(fields: { slug: { eq: $slug } }) {
      html
      frontmatter {
        title
      }
    }
  }
`;

실제 내가 사용하고 있는 lumen theme에서 post component는 아래와 같이 나타난다. posts를 뿌려주는 post component로 링크를 포함하여 제목 등 을 보여주도록 되어있다.

// @flow strict
import React from "react";
import { Link } from "gatsby";
import Comments from "./Comments";
import Content from "./Content";
import Tags from "./Tags";
import styles from "./Post.module.scss";
import type { Node } from "../../types";

type Props = {
  post: Node,
};

const Post = ({ post }: Props) => {
  const { html } = post;
  const { tagSlugs, slug } = post.fields;
  const { tags, title } = post.frontmatter;

  return (
    <div className={styles["post"]}>
      <Link className={styles["post__home-button"]} to="/">
        List
      </Link>

      <div className={styles["post__content"]}>
        <Content body={html} title={title} />
      </div>

      <div className={styles["post__footer"]}>
        {tags && tagSlugs && <Tags tags={tags} tagSlugs={tagSlugs} />}
      </div>

      <div className={styles["post__comments"]}>
        <Comments postSlug={slug} postTitle={post.frontmatter.title} />
      </div>
    </div>
  );
};

export default Post;

Gatsby의 플러그인을 사용하여 데이터를 소스 및 변환하는 방법, GraphQL을 사용하여 데이터를 페이지에 맵핑하는 방법 각 페이지의 데이터를 조회하는 페이지 템플리트 구성 요소를 빌드하는 방법등을 알아보았다.

다음 post에서는 gatsby-browser.js 에 대해서 알아보겠다. css와 style에 대한 정보를 가지고 다룬다.

마무리

gatsby에서 root에서 보면 크게 관리되는 파일이 4개로 파악된다.

  1. gatsby-browser.js
  2. gatsby-config.js
  3. gatsby-node.js
  4. gatsby-ssr.js

지금 3번부터 보고 있는데 차근차근 다 봐야 이해가 될듯싶다. 참고해서 보도록 해봅시당

Reference