Gatsby.jsでnetlify cmsを使ってみる

公開:2021/02/15
更新:2021/02/16
10 min読了の目安(約9200字TECH技術記事

備忘録で書きます。
参考サイト → https://developer.okta.com/blog/2020/02/18/gatsby-react-netlify

前提条件

pcにgatsbyが既に入っている
環境はwindowsでもmacでもどちらでもできました。

gatsbyでhello world

gatsbyで一番シンプルなテンプレートをインストールします。

git clone https://github.com/gatsbyjs/gatsby-starter-hello-world hello
cd hello
npm install

gatsby develop か npm start でサーバーを立ち上げます。(同じですが、私は npm start )

npm start

localhost 8000にてhello worldが出てきます!!

gatsby-plugin-netlify-cmsをインストールする

今回は最新バージョンではなく、上の参考URLの記事と同じバージョンを使用します。

npm i netlify-cms-app@2.11.20 gatsby-plugin-netlify-cms@4.1.40

エディタを開いて、一番うえの階層にあるgatsby-config.jsにインストールしたプラグインを下のように書き込む

gatsby-config.js
module.exports = {
  plugins: [
    `gatsby-plugin-netlify-cms`,
  ],
}

static/adminのようにstaticフォルダにadminフォルダを作成して、その中にconfig.ymlを作成する、名前は間違えないようにする

static/admin/config.yml
backend:
  name: test-repo
  
media_folder: static/assets
public_folder: /assets
  
collections:
  - name: post
    label: Post
    folder: post
    create: true
    slug: "{{year}}-{{month}}-{{day}}-{{slug}}"
    fields:
      - {label: "Template Key", name: "templateKey", widget: "hidden", default: "post"}
      - { name: date, label: Date, widget: datetime }
      - { name: title, label: Title }
      - { name: body, label: Body, widget: markdown }

とりあえず、保存して、再度 npm start します。
そして、localhost:8000/adminのように後ろに /adminをつけると管理画面が表示されます。

このとき、新しい記事をつくってもリロードすると消えます😂🤣😅😪😥
ですので、この後、githubに記事が残るように設定します。

githubにpushする

git clone したときに一番うえの階層に.gitという見えないフォルダが作成されているので、消してからinit → pushしていきます

rm -rf .git
git init
git add . && git commit -m "first commit"
git remote add origin ~
git push -u origin master

netlifyにデプロイする

netlifyにログインして、New site from Git をクリックする

  • Githubを選択する
  • 先ほどpushしたレポジトリを選択する
  • buildコマンドをgatsby buildに変更する
  • Deploy siteをクリックする(早いww)
  • デプロイ完了まで5~10分かかります

config.ymlを少し編集する

  • デプロイ完了後にstatic/admin/config.ymlのbackendをtest-repoから、githubに変更します。
  • repo: のところは自分のgithubアカウント名/先ほどpushしたレポジトリ名です。
static/admin/config.yml
backend:
  name: github
  repo: n-ohama/hello

編集後は必ずgit でプッシュします。プッシュすることで本番のデプロイ先のコードも自動で変わります(push後、反映されるまで5分くらいかかる)

git add . && git commit -m "テストレポからgithubに変更した" && git push

netlifyのサイトで実際に反映されたか確かめることもできます。
building → published に切り替わったら、反映完了です。

CMSの管理画面をgithubの0Authで実装する

  • リンクから0Authを設定しますGitHub Developer settings
  • New 0Auth Appをクリックする(下図)
  • Application Name → hello (何でもいいのですが、レポジトリと同じ名前のhello)
  • HomePageUrl → netlifyでデプロイした時のURL
  • Description は無視していいです
  • Authorization callback URL → https://api.netlify.com/auth/done を貼り付ける

  • clientIDをコピーして、generate new client secret をクリックして、出てきたsecretの横のクリップマークを押すことでコピー
  • netlifyの中のデプロイしたサイトの上のタブにてsite settingをクリック
  • 左のサイドバーにてaccess controlをクリックして、下にある0Authの中のinstall providerをクリックする
  • 先ほどコピーしたIDとSecretを張り付ければ完了です

サイトから管理画面を操作する

https://<myデプロイサイトURL>/adminのように後ろにadminをつけると自動で0Authしてくれます。
これで新しくPostを作ると、githubのそのリポジトリに保存されます。(記事を作成後に先ほどのようにビルドが始まります。publishedに変わるとgithubのリポジトリの一番上の階層のpostフォルダに保存される仕組みです。)

記事作成後はgit pullを必ずしましょう。

記事作成後はgit pullを必ずしましょう。

git pull することで、コンフリクトするのを防ぎます。
さらに、先ほど作ったファイルがmd形式で保存されているのを確認できます。

記事のリスト画面を作成する。

src/components/BlogRoll.jsx ファイルを作成する。

src/components/BlogRoll.jsx
import React from 'react'
import PropTypes from 'prop-types'
import { Link, graphql, StaticQuery } from 'gatsby'

class BlogRoll extends React.Component {
  render() {
    const { data } = this.props;
    const { edges: posts } = data.allMarkdownRemark;

    return (
      <div className="post-list">
        {posts &&
          posts.map(({ node: post }) => (
            <article key={post.id}>
              <header>
                <div className="title">{post.frontmatter.title}</div>
                <span className="subtitle">
                  &bull; {post.frontmatter.date}
                </span>
              </header>
              <p>
                <div className="excerpt">{post.excerpt}</div>
                <Link className="button" to={post.fields.slug}>
                  Keep Reading →
                </Link>
              </p>
            </article>
          ))}
      </div>
    )
  }
}

BlogRoll.propTypes = {
  data: PropTypes.shape({
    allMarkdownRemark: PropTypes.shape({
      edges: PropTypes.array,
    }),
  }),
};

export default () => (
  <StaticQuery
    query={graphql`
      query BlogRollQuery {
        allMarkdownRemark(
          filter: {frontmatter: {templateKey: {eq: "post"}}}
          sort: { order: DESC, fields: [frontmatter___date] }
        ) {
          edges {
            node {
              fields {
                slug
              }
              excerpt(pruneLength: 50, truncate: true)
              id
              frontmatter {
                title
                date(formatString: "MMMM DD, YYYY")
              }
            }
          }
        }
      }
    `}
    render={(data, count) => <BlogRoll data={data} count={count} />}
  />
)

src/pages/post.jsxを作成する。

src/pages/post.jsx
import React from 'react'

import BlogRoll from '../components/BlogRoll'

export default class BlogIndexPage extends React.Component {
  render() {
    return (
      <>
        <h1>Latest Posts</h1>
        <section>
          <BlogRoll />
        </section>
      </>
    )
  }
}

src/pages/index.jsxを編集する。(私はindex.jsをindex.jsxに変更しました)

src/pages/index.jsx
import React from "react"
import { Link } from 'gatsby'

export default () => {
  return (
    <>
      Hello world!
      <p><Link to="/post">View Post</Link></p>
    </>)
}

src/templates/post.jsxを作成します。(templatesフォルダは作りました。)

src/templates/post.jsx
import React from "react"
import { graphql } from "gatsby"
export default function Template({ data }) {
  const { markdownRemark } = data
  const { frontmatter, html } = markdownRemark
  return (
    <div className="post">
      <h1>{frontmatter.title}</h1>
      <h2>{frontmatter.date}</h2>
      <div
        className="post-content"
        dangerouslySetInnerHTML={{ __html: html }}
      />
    </div>
  )
}
export const pageQuery = graphql`
  query($id: String!) {
    markdownRemark(id: { eq: $id }) {
      html
      id
      frontmatter {
        date(formatString: "MMMM DD, YYYY")
        title
      }
    }
  }
`

一番うえの階層にgatsby-node.jsを作成します。(これはjsxにしなかったです)

gatsby-node.js
const path = require(`path`);
const { createFilePath } = require('gatsby-source-filesystem')

exports.createPages = async ({actions, graphql, reporter}) => {
  const {createPage} = actions;

  const blogPostTemplate = path.resolve(`src/templates/post.jsx`);

  const result = await graphql(`
    {
      allMarkdownRemark(
        filter: {frontmatter: {templateKey: {eq: "post"}}}
        sort: { order: DESC, fields: [frontmatter___date] }
        limit: 1000
      ) {
        edges {
          node {
            id
            fields {
              slug
            }
          }
        }
      }
    }
  `);

  // Handle errors
  if (result.errors) {
    reporter.panicOnBuild(`Error while running GraphQL query.`);
    return
  }

  result.data.allMarkdownRemark.edges.forEach(({node}) => {
    const id = node.id
    createPage({
      path: node.fields.slug,
      component: blogPostTemplate,
      context: {id},
    })
  })
};

exports.onCreateNode = ({ node, actions, getNode }) => {
  const { createNodeField } = actions

  if (node.internal.type === `MarkdownRemark`) {
      const value = createFilePath({ node, getNode })
      createNodeField({
          name: `slug`,
          node,
          value,
      })
  }
}

最後に、graphqlでファイル読み込むプラグインとhtmlをリマークしてくれるプラグインをいれてgatsby-config.jsのプラグインの所に宣言する。

npm i gatsby-source-filesystem gatsby-transformer-remark
gatsby-config.js
module.exports = {
  plugins: [
    `gatsby-plugin-netlify-cms`,
    `gatsby-transformer-remark`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        path: `${__dirname}/post`,
        name: `markdown-pages`,
      },
    },
  ],
}

完成図

git push で変更をデプロイする

以上のコードでエラーが出ていなければ、変更をgit pushしてあげることで、再度ビルドが始まります。5分くらい待てば、デプロイ先も自動で変更されます。このようにして、加えたいCSSなどを加えて、オリジナルサイトを作っていきましょう。

git add . && git commit -m "バックエンド完了" && git push

最後に

この記事を見て、wordpressだけではなく、たくさんのcmsサービスがWEB業界に増えていくことを望んでいます。この記事ではymlファイルに書いているように、templateKeyでpostと判断させているので、同様に固定ページなどもCMS化しながら応用することも可能です。次回はその記事を書いていこうかなと思います。