27
33

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Gatsby+microCMSで手を打つ

Last updated at Posted at 2020-04-21

Gatsby+microCMSで手を打つ

Intro

Angular…、そしてNext.js…。
SPAを開発しているのにSSRを考えないとイカン…なことが多くAngularから流れてくる人多いと思う。そんなこともあってNext.jsを始めたがページリロードすると404エラーとか…、それを解決するのにFunctionをとか導入して関数を書いてサーバー側で…とかもういいかげんにしてと思ってきた。
Nuxtにするか、とまた本買ってしまったが調べてみるとこれでもどうも同じことになるようで無駄な出費またまたあーもーとかなってるところにGatsbyって来て、情報が少ないものの「URLを直叩きしようがリロードしようが、404エラーが帰ってくることはなくなります」(Reactの最強フレームワークGatsby.jsの良さを伝えたい!!
ということなので賭けてみる。

Gatsbyプロジェクト作成

  1. node インストール
  2. git インストール
  3. gatsby-cli インストール

    npm install --global gatsby-cli
  4. プロジェクト作成

    gatsby new <プロジェクト名>
    (gatsby-default-starterがあたる)
  5. プロジェクトフォルダに移動してローカル環境立ち上げ
    gatsby develop
  6. http://localhost:8000 にアクセス

    image.png

フォルダ構造をみてみる。
image.png
とってもNextと似ているのでつい最近の苦労は無駄でなかったと救われる。
gatsby-config.jsというファイルがプラグイン管理
その他のgatsby-ほにゃらら.jsファイルはデフォルトでカラ。

package.jsonを見てみる

{
  "name": "gatsby-starter-default",
  "private": true,
  "description": "A simple starter to get up and developing quickly with Gatsby",
  "version": "0.1.0",
  "author": "Kyle Mathews <mathews.kyle@gmail.com>",
  "dependencies": {
    "gatsby": "^2.20.12",
    "gatsby-image": "^2.3.1",
    "gatsby-plugin-manifest": "^2.3.3",
    "gatsby-plugin-offline": "^3.1.2",
    "gatsby-plugin-react-helmet": "^3.2.2",
    "gatsby-plugin-sharp": "^2.5.3",
    "gatsby-source-filesystem": "^2.2.2",
    "gatsby-transformer-sharp": "^2.4.3",
    "prop-types": "^15.7.2",
    "react": "^16.12.0",
    "react-dom": "^16.12.0",
    "react-helmet": "^6.0.0"
  },
  "devDependencies": {
    "prettier": "2.0.4"
  },
・・・以下略・・・

reactから派生したんだなとわかる。

microCMSとの連携

ヘッドレスCMSはmicroCMSが評判が良いようなのでこれで。

  1. microCMS用のプラグインをインストールする。
$ yarn add gatsby-source-microcms
  1. つぎに gatsby-config.jsを編集する
・・・前略・・・
    `gatsby-plugin-sharp`,
    {
      resolve: `gatsby-plugin-manifest`,
      options: {
        name: `gatsby-starter-default`,
        short_name: `starter`,
        start_url: `/`,
        background_color: `#663399`,
        theme_color: `#663399`,
        display: `minimal-ui`,
        icon: `src/images/gatsby-icon.png`, // This path is relative to the root of the site.
      },
    },
// 追加↓
    {
      resolve: "gatsby-source-microcms",
      options: {
        apiKey: "X-API-KEY",
        serviceId: "guitar-club",
        endpoint: "news",
      },
    },
// 追加↑
  ],
}

micorCMSのAPI-KEY, サービスID、エンドポイントをoptions:{...}に書けばよいようである。書かないでgatsby developしてもエラーでたち上がらない。

なのでmicroCMSの設定を。

microCMS準備

microCMSのサイトはこちら→ https://microcms.io/
ここでアカウント作成してログイン。
ここでは医療系情報サイトをイメージして、一般情報、患者さん向け、医師向け、といったカテゴリーがあり、それぞれのカテゴリーに多くの情報ページがぶらさがる単純な2階層のWebサイトをイメージして作ってみる。

まずはサービス名とサービスIDを入力。サービスIDはエンドポイントのサブドメインになる(※ https://<サービス名>.microcms.io/ となる)。自分のプロジェクト名とかサイト名がいいだろうわかりやすいし。たとえばhogehoge.jpというサイトだったらhogehogeとか。
image.png

次にコンテンツを作成する。まずはカテゴリーというAPIを作る。左端メニューの「コンテンツ ✙」の✙をクリック。
image.png

カテゴリー、categoryと入力
image.png

リスト形式をえらぶ
image.png

スキーマをつくる。
image.png

追加する、をクリック
image.png

患者向けカテゴリーとしてpatientsと入力した。公開ボタンをクリック
image.png

ほかのカテゴリーも同様に追加していく。ここでは医師向けとしてdoctors、一般情報としてbasicsと。
image.png

次にカテゴリーの下にぶらさげるコンテンツを作っていく。
またコンテンツ✙をクリックして、記事コンテンツ、articlesと入力
image.png

リスト形式を選択
image.png

スキーマをつくっていく。このように。
image.png

種類とあるが、だいたい良く知ったようなものだ。テキストフィールドとかテキストエリアとか。ブログみたくリッチに編集したかったらリッチエディタで画像やリンクを張ったりもできる。カラーピッカーはまだないようだが・・・
image.png

最後にカテゴリーフィールドをつくる。種類は「複数コンテンツ参照」というのを選び、さっき作った「カテゴリー」APIを選んで決定。
image.png

作成できたら、APIリファレンスをクリックしてみる。
image.png

GET /articles/{CONTENT_ID}とあるが、つまりエンドポイントはhttps://<サービスID>.microcms.io/api/v1/articles/になる。gatsbyの場合、gatsby-config.jsのendpoint:に"articles"とだけ書けばいいが、Next.jsなどではgetInitialProps()で

const res = await axios.get(`https://<サービスID>.microcms.io/api/v1/articles/`,
key
)

のようにしなければならないようである。参考:Next.js + microCMS + NetlifyでJAMstackな世界に入門する

APIキーもここに載ってる。表示ボタンをクリックして表示させてコピーして使う。


次にAPI設定をクリック。
image.png

ここでさっき作ったフィールドを削除、追加、編集できる。なので最初は適当にタイトルとか内容(コンテンツ)とかとかまあ適当に・・・
image.png

あとはブログみたく中身をいれるだけ。入力したら公開をクリック。
image.png

「カテゴリー」フィールドは患者さん向けのpatientsにした(入力するときpatients, doctors, basicsから選ぶ)。「紹介アイコン」フィールドは種類を「画像」にしたpictというフィールドである。
image.png

このようにして、カテゴリーpatientsの記事を2つ作ってみた。
患者さん向け記事①
患者さん向け記事②
image.png

###ではコーディング
####各記事紹介ページを作成

まずはgatsby-config.jsにAPI、サービスID、エンドポイントを設定。
image.png

pagesの下にpatients.jsを作成、以下のようにコード。

// pages/patient.js
import React from "react"
import { graphql } from "gatsby"

import Layout from "../components/layout"
import SEO from "../components/seo"


const PatientsPage = ({ data }) => (
 <Layout>
   <SEO title="患者の方へ" />

   {data.allMicrocmsArticles.edges.map(edge => {
     const articles = edge.node
     const category = edge.node.category[0].name
     console.log('◆categoryは ' + category)

     if (category == 'patients') {      //カテゴリーが患者さん用の場合表示
       return (
        <React.Fragment key={articles.id}>
         <div>
             <h2>{articles.title}</h2>
             <p>{articles.feature}</p>
           <img
             src={articles.pict.url}
             width={110}
             height={110}
             alt="pict画像"
           />
         </div>
         <div>
             {articles.category.map(category => (
               <React.Fragment key={category.id}>
                 <span>カテゴリー:{category.name}</span>
               </React.Fragment>
             ))}
        </div>
        <hr />
       </React.Fragment>
       )
     } else { return }
   })}
 </Layout>
)

export const query = graphql`
 {
    allMicrocmsArticles(
     sort: { fields: [createdAt], order: DESC }
   ) {
     edges {
       node {
         id
         title
         title_origin
         category {
           id
           name
         }
         pict {
           url
         }
         body
         feature
       }
     }
   }
 }
`

export default PatientsPage

そして
gatsby developで立ち上げてhttps://localhost:8000/patientsにアクセスする。ふたつの記事のタイトルと紹介文と紹介画像が降順で表示されている。
image.png

GraphQLというのはよくわからんがこんな書き方をするのだなあ、と。

// pages/patients.js
・・・・・・

export const query = graphql`
 {
    allMicrocmsArticles(
     sort: { fields: [createdAt], order: DESC }
   ) {
     edges {
       node {
         id
         title
         title_origin
         category {
           id
           name
         }
         pict {
           url
         }
         body
         feature
       }
     }
   }
 }
`
・・・・・・

http://localhost:8000/___graphqlにアクセスしてみる。するとGraphQLで受け取ってるデータとデータ構造が見れる。
image.png

allMicrocmsArticlesのedgesのnodeに記事のすべてが詰まってる。
image.png

GraphQLでうけとったデータをmapで回してじゅんぐりに表示、ということである。

個別記事の全表示ページを作成

動的なページを作成する際にはデフォではカラだったgatsby-node.jsファイルにコードする(えっ?)。そういうキマリ。

// gatsby-node.js
const path = require("path")

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

 const result = await graphql(
   `
     {
        allMicrocmsArticles {
         edges {
           node {
             id
             title
             title_origin
             category {
                id
                name
             }
             body
             feature
             pict {
                 url
             }
           }
         }
       }
     }
   `
 )

 if (result.errors) {
   throw result.errors
 }

 result.data.allMicrocmsArticles.edges.forEach(edge => {
     //上記のGraphQLでcategoryを書いてないがnode.categoryを掴めるようだ
     const categoryName = edge.node.category[0].name
     switch (categoryName) {
         case 'patients':  // categoryがpatientsだったらサブパスをpatientsに
             subDir = '/patients/'+ edge.node.id
             break;
         case 'doctors':  // categoryがdoctorsだったらサブパスをdoctorsに
             subDir = '/doctors/'+edge.node.id
             break;
         default:
             subDir = '/articles/'+edge.node.id
     }
   createPage({
     //path: `/patients/${edge.node.id}`,
     path: `${subDir}`,
     component: path.resolve(
       "./src/templates/article.js"
     ),
     context: {
       id: edge.node.id,
     },
   })

 })
}

動的なページを作成するためにGatsbyにはcreatePagesというAPIが用意されてて、上のコードで肝になるのはそのcreatePages関数の中だけ。わたしは患者向け記事と医師向け記事と…でサブパスを分けたかったのでSwitch文があるが、単純に以下のようにシンプルでよい。

 result.data.allMicrocmsArticles.edges.forEach(edge => {
   createPage({
     path: `/articles/${edge.node.id}`,
     component: path.resolve(
       "./src/templates/article.js"
     ),
     context: {
       id: edge.node.id,
     },
   })

 })

component: path.resolve( "./src/templates/article.js" )
ではテンプレートビューファイルであるarticle.jsを指定してる。次のステップで作成する。
作成先がtemplatesフォルダになるのはそういうキマリかもしくは慣習。

context: { id: edge.node.id, }
では記事データのIDを指定している。こう書くだけで次のステップで作成するテンプレートに値渡しできるようである。

ではtemplatesフォルダを作成。
そしてその下にarticle.jsファイルを作成(ファイル名は任意)。

//templates/article.js
import React from "react"
import { graphql } from "gatsby"

import Layout from "../components/layout"

const ArticlePost = props => {
 const post = props.data.microcmsArticles // ㊟allMicrocmsArticleでない
 return (
   <Layout>
     <div>
       <h2>{post.title}</h2>
       <h3>原文:{post.title_origin}</h3>
       <br />
       <img
         src={post.pict.url}
         width={160}
         height={110}
         alt="pict画像"
       />
       <p
         dangerouslySetInnerHTML={{
           __html: `${post.body}`,
         }}
       ></p>
     </div>
   </Layout>
 )
}

export default ArticlePost

export const query = graphql`
 query($id: String!) {
   microcmsArticles(id: { eq: $id }) {
     title
     title_origin
     body
     pict {
       url
     }
     body
   }
 }
`

34行目のmicrocmsArticles(id: { eq: $id })で、gatsby-node.jsのcontextで指定した記事IDが値渡しされている。そしてそのIDをもとにmicrocmsArticlesからデータをGraphQLで引っ張っている。個別の記事をとってきたいのでallMicrocmsArticleではないところ、注意。


さいごにpatients.jsにリンクをはる。

// pages/patients.js
・・・・・・
        <React.Fragment key={articles.id}>
         <div>
             <Link to={`/patients/${articles.id}`}>
                <h2>{articles.title}</h2>
             </Link>
             <p>{articles.feature}</p>
・・・・・・

これでgatsby developでビルドしなおすと(gatsby-node.jsファイルのコードを変更すると、変更内容にもよるがビルドしなおさないといけないみたい)詳細ページが表示されるようになる。

患者向け②をクリックしてみる
image.png

表示された。
image.png

URLはコレ

titleをURLにしたかったらedge.node.titleにすれば以下のようになるだろう。日本語がイヤだったら記事コンテンツAPIに英語タイトルなりのフィールドを追加するだけだ(半角スペースはいれないよう)
http://localhost:8000/patients/患者さん用記事②

リロードしても404エラーにならない。すばらしい。


### 補足 医師向け記事も同じようにしてふたつ作った。 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307441/3c5211a3-8f00-d40c-f582-f06a281fd8df.png)

pagesフォルダの下にdoctors.jsファイルを作成、patients.jsのコードをコピペして少し編集しただけ。microCMS側では記事を作成時、カテゴリーをdoctorsにするだけだ。
image.png

もちろん、gatsby-node.jstemplates/article.jsはなにも変更する必要ない。

// pages/doctors.js
import React from "react"
import { graphql, Link } from "gatsby"

import Layout from "../components/layout"
import SEO from "../components/seo"


const PatientsPage = ({ data }) => (
 <Layout>
   <SEO title="医師の方へ" />

   {data.allMicrocmsArticles.edges.map(edge => {
     const articles = edge.node
     const category = edge.node.category[0].name
     
     console.log('◆categoryは ' + category)
     console.log('◆articles.idは ' + articles.id)
     console.log('◆リンク先は ' + `/doctors/${articles.id}`)

     if (category === 'doctors') {      //カテゴリーが医師用の場合表示
       return (
        <React.Fragment key={articles.id}>
         <div>
             <Link to={`/doctors/${articles.id}`}>
                <h2>{articles.title}</h2>
             </Link>
             <p>{articles.feature}</p>
           <img
             src={articles.pict.url}
             width={110}
             height={110}
             alt="pict画像"
           />
         </div>
         <div>
         {articles.category.map(category => (
               <React.Fragment key={category.id}>
                 <span>カテゴリー:{category.name}</span>
               </React.Fragment>
         ))}
        </div>
        <hr />
       </React.Fragment>
       )
     }
   })}
 </Layout>
)

export const query = graphql`
 {
    allMicrocmsArticles(
     sort: { fields: [createdAt], order: DESC }
   ) {
     edges {
       node {
         id
         title
         title_origin
         category {
           id
           name
         }
         pict {
           url
         }
         body
         feature
       }
     }
   }
 }
`

export default PatientsPage

補足2

React Bootstrapとの相性もすばらしい(Reactだからアタリマエか)。参考:GatsbyにReact bootstrap導入とナビゲーションバー

補足3

GraphQLも扱いが簡素で良い。JSONデータを読んでくるてのをやったがスムーズ、簡単。RESTより確かにいいかもしれない。Queryしか試してないけど…。
参考:
10分で GraphQL 入門
GraphQL解説 (AWS AppSync)

ギャツビー最高

確かにこれでイケるかもしれない。
海外では静的サイトジェネレータならGatsbyって流れになってるようだけど、日本で知名度がイマイチな理由は資生堂ギャツビーと同じ名前が微妙だからではないだろうか?


本の宣伝

Gatsbyバージョン5>>>>改訂2版

前編の『Gatsby5前編ー最新Gatsbyでつくるコーポレートサイト』と後編の『Gatsby5後編ー最新GatsbyとmicroCMSでつくるコーポレートサイト《サイト内検索機能付き》』を合わせ、次のようなデモサイトを構築します。
https://yah-space.work


静的サイトジェネレーターGatsby最新バージョン5の基本とFile System Route APIを使用して動的にページを生成する方法を解説。またバージョン5の新機能《Slicy API》《Script API》《Head API》を紹介、実装方法も。《Gatsby Functions》での問い合わせフォーム実装やGatsby Cloudへのアップロード方法も!


Gatsby5前編ー最新Gatsbyでつくるコーポレートサイト ~基礎の基礎から応用、新機能の導入まで(書籍2,980円)



最新Gatsby5とmicroCMSを組み合わせてのコーポレートサイト作成手順を解説。《サイト内検索機能》をGatsbyバージョン4からの新機能《Gatsby Functions》と《microCMSのqパラメータ》で実装。また、SEOコンポーネントをカスタマイズしてmicroCMS APIをツイッターカードに表示させるOGPタグ実装方法も解説。


Gatsby5後編ー最新GatsbyとmicroCMSでつくるコーポレートサイト《サイト内検索機能付き》(書籍 2,790円)


27
33
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
27
33

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?