반응형

1. Tailwind CSS 와 PostCSS

npm install tailwindcss postcss autoprefixer gatsby-plugin-postcss
 

2. Tailwind CSS 초기화

npx tailwindcss init

tailwind.config.js 파일이 생성됨

3. PostCSS 설정

프로젝트 루트 디렉토리에 postcss.config.js 파일을 생성한다.

module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
}

 

4. Gatsby 설정파일에 PostCSS 플러그인 추가

gatsby-config.js

module.exports = {
  ...
  plugins: [
    `gatsby-plugin-postcss`,
    ...

 

5. Global Style 파일 생성 (src/tailwind.css)

@tailwind base;
@tailwind components;
@tailwind utilities;

6. Global CSS 를 gatsby-browser.js에 추가

/**
 * Implement Gatsby's Browser APIs in this file.
 *
 * See: https://www.gatsbyjs.com/docs/reference/config-files/gatsby-browser/
 */

// You can delete this file if you're not using it
import "./src/tailwind.css";

7. PurgeCSS 설정(Optional but Recommended for Production)

옵셔널이라고 되어있는데, 이게 되어야 정상 작동함.

/** @type {import('tailwindcss').Config} */

module.exports = {
  purge: ['./src/**/*.{js,jsx,ts,tsx}', './public/index.html'],
  darkMode: false, // or 'media' or 'class'
  theme: {
    extend: {},
  },
  variants: {
    extend: {},
  },
  plugins: [],
}
반응형
반응형

1. next.config.mjs 수정

 

- 위와 같은 package.json 이 있다고 할 때, "npm run build" 를 하면 .next 폴더가 만들어지는데, next.config.mjs파일을 아래와 같이 수정해서 out파일을 배포하도록 설정을 바꿔줘야함.

 - 이미지 등의 경로를 제대로 인식할 수 있도록 basePath를 설정합니다.  [Next.js 의 모든 URL 앞에 추가되는 기본 경로를 설정]

/** @type {import('next').NextConfig} */
const nextConfig = {
  output: 'export',
  basePath: '',
  images: {
    unoptimized: true,
  },
};

export default nextConfig;

 

예전에는 next build 후 out폴더에 static 파일들을 생성하도록 next export 명령어도 했어야 했던 것 같은데, 이번 14버전에서는 next export 대신 config파일에서 output: 'export' 를 설정해주는 것만으로도 작동합니다.

 

.next폴더와 out폴더 두개가 모두 생성되는데, netlify에 배포하는 폴더는 out 폴더입니다. 

 

2. Nelify플러그인 설치

무슨 역할을 하는지는 모르겠지만, 이것도 설치해야한다고 합니다.

npm install @netlify/plugin-nextjs

 

3. netlify.toml 생성

[build]
  command = "npm run build"
  publish = "out"

[[plugins]]
  package = "@netlify/plugin-nextjs"

 

 

이미지는 나왔는데, CSS가 아직 제대로 적용이 안되었네요. 조금 더 검토해봐야겠습니다.

 

오늘은 여기까지!

반응형
반응형

이번엔 개츠비(Gatsby) 블로그에 Disqus 댓글 기능을 추가해보도록 하겠습니다.

 

[ 목차 ]

     

    1. Disqus.com에 댓글 추가할 사이트정보 입력

     Disqus.com에 로그인 후 Site Admin 으로 이동하여 기본 정보들을 입력하여 내 사이트를 추가해줍니다. 그리고 설치방법을 찾아보면 Gatsby에 반영하는 방법이 나옵니다. [ Site Admin > 내 사이트 선택 > Installation > Gatsby 선택 ]

     

    Disqus에서는 아래와 같은 형식으로 안내를 합니다. 단 config에서 괄호가 두개 들어가야합니다. 안내와 조금 차이가 있습니다.

    import { Disqus } from 'gatsby-plugin-disqus';
    
    const Template = () => (
        /* Page contents */
    
        <Disqus
            config={{
                /* Replace PAGE_URL with your post's canonical URL variable */
                url: 'PAGE_URL',
                /* Replace PAGE_IDENTIFIER with your page's unique identifier variable */
                identifier: 'PAGE_IDENTIFIER',
                /* Replace PAGE_TITLE with the title of the page */
                title: 'PAGE_TITLE',
            }}
        />
    );

     

     

    2. 플러그인 설치

    이제 내 프로젝트로 와서 아래와 같이 기본적인 플러그인 설치를 진행해줍니다.

    npm install --save gatsby-plugin-disqus

     

    설치된 플러그인은 option과 함께 gatsby-config.js에 추가해줍니다.

    // gatsby-config.js
    module.exports = {
        plugins: [
            {
                resolve: `gatsby-plugin-disqus`,
                options: {
                    shortname: `seaofcalm-gatsby`
                }
            },
        ]
    }

     

    이제 위에서 안내받은 코드를 내 소스에 반영하면 됩니다. 자동으로 md파일들을 HTML로 변환하도록 만든 md-files.js의 소스코드를 아래와 같이 수정했습니다. GraphQL에서 필요한 데이터도 잊지않고 가져와줘야 합니다.

    import React from "react"
    import { graphql } from "gatsby"
    import { GatsbyImage, getImage } from "gatsby-plugin-image"
    import Layout from "../components/layout"
    import { Disqus } from "gatsby-plugin-disqus"
    
    export default function Template({ data }) {
      
      const { markdownRemark } = data
      const { frontmatter, html } = markdownRemark
      const thumbnailImg = getImage(frontmatter.thumbnail?.childImageSharp?.gatsbyImageData)
    
      return (
        <Layout>
          <div className="blog-post-container">
            <div className="blog-post">
              {/* <GatsbyImage 
                image={thumbnailImg} 
                alt="Thumbnail" 
                imgStyle={{ objectFit: "cover", objectPosition: "50% 50%" }}
                style={{ width: "100%`" }}
              /> */}
              <h1>{frontmatter.title}</h1>
              <h2>{frontmatter.date}</h2>
              <div dangerouslySetInnerHTML={{ __html: html }} />                   
            </div>
          </div>
          <Disqus
            config={{
              /* Replace PAGE_URL with your post's canonical URL variable */
              url: `${data.site.siteMetadata.siteUrl + frontmatter.slug}`,
              /* Replace PAGE_IDENTIFIER with your page's unique identifier variable */
              identifier: `${markdownRemark.id}`,
              /* Replace PAGE_TITLE with the title of the page */
              title: `${frontmatter.title}`,
            }}
          /> 
        </Layout>
      )
    }
    
    export const query = graphql`
      query($slug: String!) {
        markdownRemark(fields: { slug: { eq: $slug } }) {
          html
          id
          frontmatter {
            date(formatString: "MMMM DD, YYYY")        
            title  
            slug
            thumbnail {
              childImageSharp {
                gatsbyImageData
              }
            }
          }
        }
        site {
          siteMetadata {
            siteUrl
          }
        }
      }
    `

     

    <결과>

    localhost:8000에서도 잘 확인이 됩니다.

     

    반응형
    반응형

    [ 목차 ]

      구글 서치콘설에 등록하기 위해서는 3단계를 거쳐야 합니다. 

      1. sitemap.xml 

      2. robots.txt

      3. Google Search Console 등록

       

      1. Sitemap.xml 생성

      가장 먼저 sitemap.xml을 생성합니다. 생성 방법은 플러그인 추가로 쉽게 진행할 수 있습니다. gatsby-plugin-sitemap, gatsby-plugin-advanced-sitemap 플러그인을 추가해줍니다.

      npm i gatsby-plugin-sitemap
      
      // gatsby가 버전 5로 올라가면서 아래의 플러그인은 아직 설치가 안되고 있습니다.
      npm i gatsby-plugin-advanced-sitemap

      gatsby-config.js 에 플러그인을 추가해줍니다.

      module.exports = {
      	siteMetadata:{
          	siteUrl: 'https://......com/',
          },
          plugins: [
             ...
             'gatsby-plugin-sitemap'
             ...
         ],
      };

      build후 URL/sitemap-index.xml에 접속하면 sitemap을 확인할 수 있습니다.

       

      2. Robots.txt 생성

      robots.txt는 웹페이지 크롤링 봇들이 내 사이트를 크롤링을 할 때 어떤 부분을 허용하고, 어떤 부분을 제한할지 설정하는 파일입니다. 이 역시 gatsby-plugin-robots-txt 플러그인 추가로 간단히 해결할 수 있습니다.

      npm i gatsby-plugin-robots-txt

      gatsby-config.js 에 플러그인을 추가하고 설정해줍니다.

      module.exports = {
      	siteMetadata:{
          	siteUrl: 'https://......com/',
          },
          plugins: [
             ...
             'gatsby-plugin-sitemap',
             ...
             {
             	resolve: 'gatsby-plugin-robots-txt',
              options: {
              	host:'https://{my URL}.com/',
                  sitemap: 'https://{my URL}.com/sitemap-index.xml',
                  policy:[{ userAgent: '*', allow: '/'}],
              },
             },
             ...
         ],
      };

       

      3. Google Search Console 등록

      서치 콘솔에서 새로운 사이트를 등록하는 방법은 [ 여기 ]포스팅을 참조하시기 바랍니다. 이제 <meta>태그를 적용시켜줘야하는데, 기본 Gatsby Starter로 시작했다면, src/components/layout.js파일을 수정하는게 편합니다. 우선 react-helmet이라는 플러그인을 설치해줍니다.

      npm i react-helmet

      그리고 아래와 같이 <Header /> 태그의 아래쪽에 <Helmet> 컴포넌트를 이용해서 코드를 추가해줍니다

      import { Helmet } from "react-helmet"
      
      // ...
      
      return (
          <>
            <Header siteTitle={data.site.siteMetadata?.title || `Title`} />
            
            <Helmet>        
              <meta name="google-site-verification" content="{your google code}" />
            </Helmet>
            <div
              style={{
                margin: `0 auto`,
                maxWidth: `var(--size-content)`,
                padding: `var(--size-gutter)`,   
                
              }}
            >
        // ...

       

      정상 적용되면 구글 서치콘솔에서 "확인" 등 다음단계 진행 시 소유권이 확인됩니다. 

      (ps) 이 방법으로 적용이 안될 경우 seo.js파일에 직접 넣어주는 방법으로도 가능합니다.

      return (
          <>
            <title>{defaultTitle ? `${title} | ${defaultTitle}` : title}</title>
            <meta name="description" content={metaDescription} />
            <meta property="og:title" content={title} />
            <meta property="og:description" content={metaDescription} />
            <meta property="og:type" content="website" />
            <meta name="twitter:card" content="summary" />
            <meta name="twitter:creator" content={site.siteMetadata?.author || ``} />
            <meta name="twitter:title" content={title} />
            <meta name="twitter:description" content={metaDescription} />
            <meta
              key="google-site-verification"
              name="google-site-verification"
              content="인증코드" // 여기 추가
            />
            {children}
          </>
        )

       

      다음으로는 서치콘솔 화면에서 sitemap.xml을 인식시켜줍니다.

      반응형
      반응형

      사실...여러 예제와 뤼튼 AI를 이용해서 하루 종일 고생하며 방법을 찾아봤는데, 지금도 왜 되었는지 잘 모르겠습니다. 예제를 따라 해도 안되던게 갑자기 됩니다. 우선 코드만 남겨놓습니다.

       

       

       

      1. 마크다운 파일 읽어오는 옵션

      'gatsby-source-filesystem'은 기본적으로 설치되었을겁니다. 마크다운 파일들을 모아놓는 곳을 아래와 같이 설정해줍니다.

      // gatsby-config.js
      module.exports = {
        siteMetadata: { ... },
        plugins: [
          ...,
          {
            resolve: `gatsby-source-filesystem`,
            options: {
              name: `posts`,
              path: `${__dirname}/content/posts`,
            },
          },
          ...
        ],
      };

      2. gatsby-plugin-image 플러그인

      'gatsby-plugin-image' 플러그인도 기본으로 설치가 되어있을 확률이 높습니다. Gatsby에서 이미지를 렌더링 할 때 사용하는 플러그인입니다. 이미지들에 대해 자동으로 인식하여 속성정보를 생성해주지만, 가장 중요한 것 - 이미지 폴더를 지정해줘야합니다.

      module.exports = {
        ...,
        plugins: [
          `gatsby-plugin-image`,
          {
            resolve: `gatsby-source-filesystem`,
            options: {
              name: `images`,
              path: `${__dirname}/content/posts/images`,
            },
          },
          {
            resolve: `gatsby-source-filesystem`,
            options: {
              name: `posts`,
              path: `${__dirname}/content/posts`,
            },
          },

       

      3. 마크다운 파일

      아래 정도의 frontmatter를 작성해줍니다. 샘플로 몇개를 더 만들어놓습니다. 그리고 thumbnail경로에 예시 코드와 맞도록 이미지를 준비해줍니다.

      ---
      title: Todo List
      date: "2022-05-10T22:12:03.284Z"
      description: 남은 할일 목록
      slug: page1
      thumbnail: './images/page1.png'
      ---
      
      
      - 댓글기능
      - 검색최적화(SEO)
      - 카테고리 만들기

       

      4./gatsby-node.js

      이 부분에서는 이전 포스트 대비 특별히 손댈 것은 없습니다. thumbnail노드 하위의 속성은 gatsby-plugin-image 플러그인을 통해 인식된 이미지들로 인해 자동으로 생성됩니다.

      const path = require('path');
      
      exports.createPages = ({ graphql, actions }) => {
        const { createPage } = actions;
      
        const blogPostTemplate = path.resolve('src/templates/md-files.js');
      
        return graphql(`
          {
            allMarkdownRemark {
              edges {
                node {
                  fields {
                    slug
                  }
                }
              }
            }
          }
        `).then((result) => {
          if (result.errors) {
            return Promise.reject(result.errors);
          }
      
          result.data.allMarkdownRemark.edges.forEach(({ node }) => {
            createPage({
              path: node.fields.slug,
              component: blogPostTemplate,
              context: {
                slug: node.fields.slug,
              },
            });
          });
        });
      };
      
      exports.onCreateNode = ({ node, getNode, actions }) => {
        const { createNodeField } = actions;
      
        if (node.internal.type === `MarkdownRemark`) {
          const slug = path.basename(node.fileAbsolutePath, '.md');
      
          createNodeField({
            node,
            name: `slug`,
            value: `/${slug}`,
          });
        }
      };

      6. src/pages/index.js

      이전 포스팅에서 작성한 내용에서, 각 포스팅의 타이틀 스타일을 변경해주고, 표시되는 순서를 작성일의 역순정렬로 변ㄱ여하였습니다.

      import React from "react"
      import { useStaticQuery, Link, graphql } from "gatsby"
      import Layout from "../components/layout"
      
      export default ({ data }) => {
        console.log(data)
        return (
          <Layout>
            <div>
              <h1>
                A World of Hello World and Todo List
              </h1>
              <h4>{data.allMarkdownRemark.totalCount} Posts</h4>
              {data.allMarkdownRemark.edges.map(({ node }) => (
                <div key={node.id} style={{
                  marginBottom: "50px",
                }}>
                  <h2>
                    <Link to={node.fields.slug}
                      style={{
                        color: "#555",           
                        textDecoration: "none",
                      }}>
                      {node.frontmatter.title}{" "}
                      <span>
                        — {node.frontmatter.date}
                      </span>
                    </Link>
                  </h2>
                  <p>{node.excerpt}</p>
                </div>
              ))}
            </div>
          </Layout>
        )
      }
      
      export const query = graphql`
        query {
          allMarkdownRemark(sort: { fields: [frontmatter___date], order: DESC }) {
            totalCount
            edges {
              node {
                id
                frontmatter {
                  title
                  date(formatString: "DD MMMM, YYYY")
                  description
                }
                excerpt
                fields{
                  slug
                }
              }
            }
          }
        }
      `

       

      7. src/templates/md-files.js

      이부분이 마크다운 파일들을 읽어서 동일한 템플릿 형태로 표현해주는 부분입니다. 여기서 gatsby-plugin-image 플러그인에서 제공하는 GatsbyImage 컴포넌트와 getImage 메서드를 활용합니다. gatsby-plugin-image 역시 이미 설치되어있을 확률이 높습니다. 

      import React from "react"
      import { graphql } from "gatsby"
      import { GatsbyImage, getImage } from "gatsby-plugin-image"
      import Layout from "../components/layout"
      
      export default function Template({ data }) {
        
        const { markdownRemark } = data
        const { frontmatter, html } = markdownRemark
        const thumbnailImg = getImage(frontmatter.thumbnail?.childImageSharp?.gatsbyImageData)
      
        return (
          <Layout>
            <div className="blog-post-container">
              <div className="blog-post">
                <GatsbyImage image={thumbnailImg} alt="Thumbnail" />
                <h1>{frontmatter.title}</h1>
                <h2>{frontmatter.date}</h2>
                <div dangerouslySetInnerHTML={{ __html: html }} />
              </div>
            </div>
          </Layout>
        )
      }
      
      export const query = graphql`
        query($slug: String!) {
          markdownRemark(fields: { slug: { eq: $slug } }) {
            html
            frontmatter {
              date(formatString: "MMMM DD, YYYY")        
              title  
              thumbnail {
                childImageSharp {
                  gatsbyImageData
                }
              }
            }
          }  
        }
      `

       

      8. gatsby-remark-images 설치 및 설정

      gatsby-remark-images플러그인을 설치한 후 gatsby-config.js파일에 아래와 같이 추가합니다. 이 플러그인은 마크다운 파일의 이미지를 최적화하여 사용할 수 있도록 도와주는 플러그인입니다. 화면에서 이상하게 나오던 이미지들이 아래의 설정 이후정상적으로 나옵니다. 

      {
            resolve: `gatsby-transformer-remark`,
            options: {
              plugins: [
                {
                  resolve: `gatsby-remark-images`,
                  options: {
                    maxWidth: 800,
                  },
                },
              ],
            },
          },

       

      <결과>

      반응형
      반응형

       

      정적사이트 생성기(SSG, Static Site Generator)에 대해 공부하다보니 다시 Gatsby에 대한 흥미가 돌기 시작해서 오랫만에 Gatsby로 프로젝트를 만들어봤습니다. 예전에 이걸 공부했던 적이 있었나 싶을 정도로 하나도 기억이 안나더군요. React에 대한 두려움으로 React 계통의 프레임워크들은 무조건 멀리했었던 것 같기도 하고, 사실은 Gatsby, GraphQL에 대해 정확히 공부한적이 없었던 것 같기도 하네요. 그래서 오늘은 설치하고 마크다운 문서 표기하기까지 알게된 내용을 정리해볼까 합니다.

       

      [ 목차 ]

         

        1. Gatsby란?

        Gatsby는 서두에 말했듯이 React에 기반한 정적사이트 생성기(SSG, Static Site Generator)입니다. 예전부터 Ruby on Rails로 작성된 Jekyll 이 가장 많이 사용되었었는데, React에 기반한 점, GraphQL을 사용하여 이미지, 컨텐츠 등 데이터를 빠르고 쉽게 반영할 수 있는점 등으로 매우 큰 인기를 끌고 있습니다. 거기다 다양한 테마를 적용한 스타터 킷이 존재하여 사용자 편의성을 지원하고 있습니다. 이전 포스트(정적 사이트 생성기 (SSG, Static Site Generator) 로 나만의 블로그를 만들어보자 (tistory.com))에서도 소개했듯이 다양한 SSG가 존재하지만 그 중에서도 Gatsby는 만들어진 이래 항상 최상위권을 유지하고 있습니다. 

          이제 한단계씩 시작해보겠습니다. 이번 프로젝트에서도 마크다운 문서들을 이용해 각 URL별로 문서를 표시하는 기능을 만들어보겠습니다.

         

         

        2. 설치

        아래의 명령어로 글로벌 설치를 합니다.

        npm i -g gatsby-cli

         

        3. 프로젝트 생성

        gatsby new [프로젝트(폴더) 이름]
        
        //현재 폴더에 프로젝트를 구성할 경우 폴더명(".") 입력
        gatsby new .  // 개인적으로 이 방법 자주씀

         참고로, 스타터킷으로 시작하는 것도 좋은 방법입니다.(Starters Library | Gatsby (gatsbyjs.com)) 하지만 저는 아직 실력이 부족하여 남이 써놓은 코드를 아직 수정을 못하다보니, 직접 하나씩 만들어가고 있습니다.

         

        4. 결과 보기

        package.json에서 "script"부분을 조금 수정하여, develop 대신 dev로 간단히 바꿔놓았습니다.

        //from
        "develop": "gatsby develop"
        
        // to
        "dev": "gatsby develop",

        이제 아래의 명령어로 시작하면..

        npm run dev

        아래와 같이 2개의 URL이 주어지는데, 첫번째 URL이 결과 화면이고, 두번째는 graphql 관련 페이지입니다.

         

         

         

        5. Index페이지에서 마크다운 문서 리스트 보이기

        다음으로 Index페이지에 마크다운 문서들의 목록을 보여주도록 구성하겠습니다. 우선 마크다운 샘플 문서를 3개정도 만들어줍니다. 위치는 루트 디렉토리 내에 /content/posts폴더를 새로 만들어줍니다.

         

        [content/posts/post1.md] 새 폴더와 함께 새 파일 생성

        ---
        title: My Markdown Page
        date: "2023-07-25T22:12:03.284Z"
        description: This is an example of a Markdown page.
        slug: page1
        ---
        
        # My Markdown Page
        
        This is an example of a Markdown page. You can use Markdown syntax to format the content of your pages. 
        
        ## Subheading
        
        Here's another section with a subheading. You can use various formatting options such as **bold**, *italic*, and `code` to add emphasis.

        비슷하게 post2.md, post3.md파일을 생성해줍니다.

        slug는 추후 우리가 접속하게될 url주소입니다. post2.md에는 slug: page2, post3.md에는 slug: page3라고 작성합니다.

         

        [gatsby-config.js파일 plugin설정]

        gatsby-config.js파일에서 두가지 설정을 해주어야 합니다.

        첫째는 `gatsby-source-filesystem` 플러그인으로 posts폴더를 인식시켜주는 것이고,

        둘째는 `gatsby-transformer-remark` 를 이용해 마크다운 문서를 HTML로 변환시켜주는 것입니다.

         

        <posts 폴더 인식>

        gatsby-config.js파일의 plugin 부분을 보면 `gatsby-source-filesystem`을 이용해 images폴더를 설정한 부분이 있습니다. 이미 해당 플러그인이 설치가 되있다는 얘기입니다. package.json에서도 확인이 가능합니다. 그 아래쪽에 한단락을 복사해서 posts폴더를 인식할 수 있도록 설정을 추가합니다.

        module.exports = {
          siteMetadata: {
            title: `Gatsby Default Starter`,
            description: `Kick off your next, great Gatsby project with this default starter. This barebones starter ships with the main Gatsby configuration files you might need.`,
            author: `@gatsbyjs`,
            siteUrl: `https://gatsbystarterdefaultsource.gatsbyjs.io/`,
          },
          plugins: [
            `gatsby-plugin-image`,
            {
              resolve: `gatsby-source-filesystem`,
              options: {
                name: `images`,
                path: `${__dirname}/src/images`,
              },
            },
            { // 추가 여기서부터
              resolve: `gatsby-source-filesystem`,
              options: {
                name: `posts`,
                path: `${__dirname}/content/posts`,
              },
            }, // 여기까지
            `gatsby-transformer-sharp`,
            `gatsby-plugin-sharp`,
            {
              resolve: `gatsby-plugin-manifest`,
              options: {
                name: `gatsby-starter-default`,
                short_name: `starter`,
                start_url: `/`,
                background_color: `#663399`,
                // This will impact how browsers show your PWA/website
                // https://css-tricks.com/meta-theme-color-and-trickery/
                // theme_color: `#663399`,
                display: `minimal-ui`,
                icon: `src/images/gatsby-icon.png`, // This path is relative to the root of the site.
              },
            },
          ],
        }

        <마크다운 문서 변환>

        마크다운 문서 변환을 위해서는 `gatsby-transformer-remark` 플러그인을 우선 설치해야합니다.

        npm i gatsby-transformer-remark

        다음으로 gatsby-config.js파일에 해당 플러그인이 적용되도록 한줄 추가해넣습니다.

        <src/pages/index.js 파일 수정>

        index.js파일을 아직은 잘 모르겠지만, 아래와 같이 수정합니다. 아래부분은 GraphQL을 이용해 내가만든 컨텐츠(md파일들)로부터 정보를 가져오는 부분입니다.

        import React from "react"
        import { Link, graphql } from "gatsby"
        // import { css } from "@emotion/core"
        // import { rhythm } from "../utils/typography"
        import Layout from "../components/layout"
        
        export default ({ data }) => {
          console.log(data)
          return (
            <Layout>
              <div>
                <h1>
                  Amazing Pandas Eating Things
                </h1>
                <h4>{data.allMarkdownRemark.totalCount} Posts</h4>
                {data.allMarkdownRemark.edges.map(({ node }) => (
                  <div key={node.id}>
                    <h3>
                      {node.frontmatter.title}{" "}
                      <span>
                        — {node.frontmatter.date}
                      </span>
                    </h3>
                    <p>{node.excerpt}</p>
                  </div>
                ))}
              </div>
            </Layout>
          )
        }
        
        export const query = graphql`
          query {
            allMarkdownRemark {
              totalCount
              edges {
                node {
                  id
                  frontmatter {
                    title
                    date(formatString: "DD MMMM, YYYY")
                  }
                  excerpt          
                }
              }
            }
          }
        `

        <결과>

        아래와 같이 결과와 내용으로 구성된 리스트가 잘 나타납니다.

         

        6. 마크다운 문서 보이기

        리스트는 나오는데, 각 포스트별 페이지도 없고 링크도 안됩니다. 이 부분을 추가해보도록 하겠습니다.

         

        </src/templates/md-files.js>

        우선 md-files.js라고 템플릿 파일을 하나 생성합니다. GraphQL로부터 값들을 가져와 화면에 뿌려주는 역할을 합니다. 

        import React from "react"
        import { graphql } from "gatsby"
        import Layout from "../components/layout"
        
        export default function Template({ data }) {
          // console.log(data)
          const { markdownRemark } = data
          const { frontmatter, html } = markdownRemark
          return (
            <Layout>
              <div className="blog-post-container">
                <div className="blog-post">
                  <h1>{frontmatter.title}</h1>
                  <h2>{frontmatter.date}</h2>
                  <div dangerouslySetInnerHTML={{ __html: html }} />
                </div>
              </div>
            </Layout>
          )
        }
        
        export const query = graphql`
          query($slug: String!) {
            markdownRemark(fields: { slug: { eq: $slug } }) { 
              html
              frontmatter {
                date(formatString: "MMMM DD, YYYY")        
                title
              }
            }
          }
        `

        markdownRemark(fields: {slug: {eq: $slug} }) 부분은 slug를 키 값으로 하여 각 포스트의 정보를 가져오라는 의미입니다.

         

        <gatsby-node.js>

        page를 생성해주는 템플릿 파일을 만들었으면, 이제 적용해주어야 합니다. 아래와 같이 gatsby-node.js를 작성하여 실행되도록 합니다. createPages는 gatsby에서 페이지를 생성할 때 실행되고, onCreateNode함수는 노드가 생성될 때마다 실행됩니다. onCreateNode 함수에서 마크다운 파일을 읽어 Slug 값을 추출하고, createNodeField 함수를 사용하여 노드에 Slug 값을 추가합니다. 

        const path = require('path');
        
        exports.createPages = ({ graphql, actions }) => {
          const { createPage } = actions;
        
          const blogPostTemplate = path.resolve('src/templates/md-files.js');
        
          return graphql(`
            {
              allMarkdownRemark {
                edges {
                  node {
                    fields {
                      slug
                    }
                  }
                }
              }
            }
          `).then((result) => {
            if (result.errors) {
              return Promise.reject(result.errors);
            }
        
            result.data.allMarkdownRemark.edges.forEach(({ node }) => {
              createPage({
                path: node.fields.slug,
                component: blogPostTemplate,
                context: {
                  slug: node.fields.slug,
                },
              });
            });
          });
        };
        
        exports.onCreateNode = ({ node, getNode, actions }) => {
          const { createNodeField } = actions;
        
          if (node.internal.type === `MarkdownRemark`) {
            const slug = path.basename(node.fileAbsolutePath, '.md');
        
            createNodeField({
              node,
              name: `slug`,
              value: `/${slug}`,
            });
          }
        };

         

        < /src/pages/index.js >

        index.js파일도 링크가 가능하도록 추가 수정해줍니다.

        //~~~
        export default ({ data }) => {
          console.log(data)
          return (
            <Layout>
              <div>
                <h1>
                  Amazing Pandas Eating Things
                </h1>
                <h4>{data.allMarkdownRemark.totalCount} Posts</h4>
                {data.allMarkdownRemark.edges.map(({ node }) => (
                  <div key={node.id}>
                    <h3>
                      <Link to={node.fields.slug}> <!-- 추가 -->
                        {node.frontmatter.title}{" "}
                        <span>
                          — {node.frontmatter.date}
                        </span>
                      </Link> <!-- 추가 -->
                    </h3>
                    <p>{node.excerpt}</p>
                  </div>
                ))}
              </div>
            </Layout>
          )
        }
        
        export const query = graphql`
          query {
            allMarkdownRemark {
              totalCount
              edges {
                node {
                  id
                  frontmatter {
                    title
                    date(formatString: "DD MMMM, YYYY")
                  }
                  fields{ <!-- 여기부터 추가 -->
                    slug
                  } <!-- 여기까지 -->
                  excerpt          
                }
              }
            }
          }
        `

        <결과>

        링크가 가능하도록 변경되었고,,,

         

        클릭하면 개별 페이지 링크로 전환되는 것까지 확인이 됩니다.

        반응형
        반응형

        1. 라이브러리 설치

        yarn add redux react-redux @reduxjs/tookit

         

        2. index.js

        Reducer 연결 및 store 생성

        import React from "react";
        import ReactDOM from "react-dom";
        import "./index.css";
        import App from "./App";
        import reportWebVitals from "./reportWebVitals";
        
        import { configureStore } from "@reduxjs/toolkit";
        import rootReducer from "./reducers";
        import { Provider } from "react-redux";
        
        const store = configureStore({ 
            reducer: rootReducer,
            devTools: process.env.NODE_ENV !== "production",
        });
        
        ReactDOM.render(
          <React.StrictMode>
            <Provider store={store}>
              <App />
            </Provider>
          </React.StrictMode>,
          document.getElementById("root")
        );
        
        // If you want to start measuring performance in your app, pass a function
        // to log results (for example: reportWebVitals(console.log))
        // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
        reportWebVitals();

         

        3. App.js

        import React from "react";
        import "./App.css";
        import Counter from './components/Counter';
        
        const App = () => {
          return (
            <div>
              <Counter />
            </div>
          );
        };
        export default App;

        4. reducers/counter.js

        import { createAction, createReducer } from "@reduxjs/toolkit";
        
        const INCREASE = "counter/INCREASE";
        const DECREASE = "counter/DECREASE";
        
        export const increase = createAction(INCREASE);
        export const decrease = createAction(DECREASE);
        
        const initialState = {
          number: 0,
        };
        
        const counter = createReducer(initialState, {
          [INCREASE]: (state, action) => ({ number: state.number + 1 }),
          [DECREASE]: (state, action) => ({ number: state.number - 1 }),
        });
        
        export default counter;

         

        5.reducers/index.js

        import { combineReducers } from "redux";
        import counter from './counter';
        
        const rootReducer = combineReducers({
          counter,
        })
        
        export default rootReducer;

        6. components/Counter.jsx

        import React from "react";
        import { increase, decrease } from "../reducers/counter";
        import { useSelector, useDispatch } from "react-redux";
        
        const Counter = () => {
          
          const number = useSelector((state) => state.counter.number);
          const dispatch = useDispatch();
          return (
            <div>
              <h1>{number}</h1>
              <div>
                <button onClick={() => dispatch(increase())}>+1</button>
                <button onClick={() => dispatch(decrease())}>-1</button>
              </div>
            </div>
          );
        };
        
        export default Counter;
        반응형
        반응형

        1. 지도에서 좌표-주소 변환

        geocoder 라는 것을 사용해야하는데, services라이브러리를 써야합니다. 라이브러리는 api 요청할 때 url에 추가해서 보내면 됩니다. (kakao 예제에서 제공하는 cluster, drawing도 함께 추가해 넣었습니다.)

        <script type="text/javascript" src="//dapi.kakao.com/v2/maps/sdk.js?appkey=내api키&libraries=services,clusterer,drawing"></script>

         

        2. 우선 화면에 무언가 표시를 해봅시다.

        예제는 kakao에서 제공되는 kakao 제주 사옥을 찾는 것 같습니다.

        </src/container/MapContainer.js>

        import React, { useEffect } from 'react';
        
        const { kakao } = window;
        
        const MapContainer = () => {
        
          useEffect(() => {
            const container = document.getElementById('myMap');
            const options = {
              center: new kakao.maps.LatLng(35.12, 129.1),
              level: 3
            };
            // 지도를 생성합니다.
            const map = new kakao.maps.Map(container, options);
            // 주소-좌표 변환 객체를 생성합니다.
            const geocoder = new kakao.maps.services.Geocoder();
            // 주소로 좌표를 검색합니다..
            geocoder.addressSearch('제주특별자치도 제주시 첨단로 242', function (result, status) {
        
              // 정상적으로 검색이 완료됐으면 
              if (status === kakao.maps.services.Status.OK) {
          
                var coords = new kakao.maps.LatLng(result[0].y, result[0].x);
          
                // 결과값으로 받은 위치를 마커로 표시합니다
                var marker = new kakao.maps.Marker({
                  map: map,
                  position: coords
                });
          
                // 인포윈도우로 장소에 대한 설명을 표시합니다
                var infowindow = new kakao.maps.InfoWindow({
                  content: '<div style="width:150px;color:red;text-align:center;padding:6px 0;">내가 썼지롱</div>'
                });
                infowindow.open(map, marker);
          
                // 지도의 중심을 결과값으로 받은 위치로 이동시킵니다
                map.setCenter(coords);
              }
            })
          }, []);
        
          return (
            <div id='myMap' style={{
              width: '800px', 
              height: '800px'
            }}></div>
          );
        }
        
        export default MapContainer;

        <결과>

        아직 기능들을 알 수는 없지만, 뭔가 써집니다.

        반응형

        + Recent posts