[JAMstack]Gatsby + Netlify + Contentfulの構成を試してみた

## 何ができるのか

- Webページを作ってネット上に公開できる
- Webページに表示するコンテンツを管理コンソール上で編集できる
- 管理コンソール上でコンテンツを更新すると自動でビルド/デプロイしページを最新化できる

## 実現できたこと

- 以下のフローでWebページに表示するコンテンツを更新できる

1. Contentfulの管理コンソールでコンテンツを登録
<img width="516" alt="step1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/6684e7ff-0870-060f-ac90-a69f49cb9d8f.png">

1. Gatsbyで作ったReactアプリをNetlifyでホスティング(ビルド時にContentfulからデータを取得している)
<img width="345" alt="step2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/2feb07be-6d53-6f17-a216-be662a913e6b.png">

1. Contentfulの管理コンソールでコンテンツを追加/更新
<img width="481" alt="step3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/0cb10146-c6c4-6f09-1b32-412eb9314c6c.png">

1. NetlifyがContentfulの更新をトリガーにbuild/deployを実行
<img width="489" alt="step4.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/d788a6c2-49ae-cf41-fa7e-75a2189bab1c.png">

1. Webページをリロードすると最新版に反映されてる！
<img width="347" alt="step5.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/d0c57e75-a042-37bb-633e-79ba16d73eec.png">


## 登場人物の紹介

### Gatsby

- https://www.gatsbyjs.org/
- 静的サイトジェネレーター
- Reactを拡張したフレームワークのようなもの
- ビルド時に外部からコンテンツを取り込むことができるのが特徴的

### Netlify

- https://www.netlify.com/
- ホスティングサービス
- Githubなどのリポジトリと連携しclone/build/deployを行うことができる
- 指定したブランチにpushされた時やPRが出された時など、簡単にトリガーを設定できるのが便利

### Contentful

- https://www.contentful.com/
- HeadlessCMS
- 管理コンソール上でDBのデータを更新できるようなイメージ
- 登録したデータはAPIでアクセスできる

## やったこと

### Contentfulにデータを登録

- Contentfulにログインし以下の手順を実施
- サイドメニューを開いて`+ Create space`からSpaceを作成する
<img width="355" alt="スクリーンショット 2019-09-06 8.22.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/08b65c06-125b-9550-1974-da58fbfa5e60.png">
<img width="391" alt="スクリーンショット 2019-09-06 8.24.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/22abed51-7f88-d621-0c53-cd7bd56830ed.png">
<img width="386" alt="スクリーンショット 2019-09-06 8.24.40.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/f86d3ffa-0b59-2d25-3144-6cb77f5ab267.png">
<img width="387" alt="スクリーンショット 2019-09-06 8.24.47.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/3dfcc77e-4ecc-4332-b973-853d74ca8678.png">

- `Add content type`からcontent type(RDBのテーブルのような概念)を追加する
<img width="477" alt="スクリーンショット 2019-09-06 8.27.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/16e4173e-0bc5-564b-e99f-f66f7aa2a6f3.png">
<img width="351" alt="スクリーンショット 2019-09-06 8.28.15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/d15c1956-705a-eb4a-1815-df36c0abbece.png">

- `Add field`からfieldを追加
<img width="294" alt="スクリーンショット 2019-09-06 8.28.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/a6d68fa1-2bc7-1d19-3c34-f7cd4f3a8c53.png">
<img width="330" alt="スクリーンショット 2019-09-06 8.29.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/acf062e1-0419-d7d7-707b-ae034aa053c1.png">
<img width="372" alt="スクリーンショット 2019-09-06 8.29.43.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/b31887ec-d7af-27b3-3313-0784a4877692.png">
<img width="375" alt="スクリーンショット 2019-09-06 8.30.01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/794b8180-a01f-7689-b63c-9f5f28b077e3.png">

- `Add User`からUserを追加する
<img width="484" alt="スクリーンショット 2019-09-06 18.34.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/d7539e84-a07e-a8e9-d383-6a7e685e87cb.png">
<img width="600" alt="スクリーンショット 2019-09-06 18.35.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/c8a82338-3de1-6f18-c1f1-e51f9dc1efe8.png">
<img width="600" alt="スクリーンショット 2019-09-06 18.35.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/c4cf2038-5af6-0897-1af8-8c01b5eeafcb.png">


### GatsbyでReactアプリを作成

#### アプリのを作成

- GatsbyのCLIをインストール

```bash
npm install -g gatsby-cli
```

- アプリケーションの雛形を生成

```bash
gatsby new gatsby-sample
```

- アプリを起動してみる

```bash
cd gatsby-sample
npm start
```

- ※自分の場合`npm start`したときに以下のようなエラーが発生した

<details><summary>エラーの内容</summary><div>

```bash
npm ERR! code ELIFECYCLE
npm ERR! errno 7
npm ERR! gatsby-starter-default@0.1.0 develop: `gatsby develop`
npm ERR! Exit status 7
npm ERR!
npm ERR! Failed at the gatsby-starter-default@0.1.0 develop script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/ozaki/.npm/_logs/2019-09-06T09_45_07_039Z-debug.log
npm ERR! code ELIFECYCLE
npm ERR! errno 7
npm ERR! gatsby-starter-default@0.1.0 start: `npm run develop`
npm ERR! Exit status 7
npm ERR!
npm ERR! Failed at the gatsby-starter-default@0.1.0 start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/ozaki/.npm/_logs/2019-09-06T09_45_07_063Z-debug.log
```
</div></details>

- `/private/etc/hosts`に以下の内容を記載することで解決した

```
127.0.0.1   localhost
```

- アプリが起動しhttp://localhost:8080/ にアクセスすると以下の画面が表示される
<img width="480" alt="スクリーンショット 2019-09-06 18.51.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/fbd60bc8-e9f3-d9cc-f4a2-fc9d259ddd3e.png">

#### ContentfulのAPIキーを取得

- Contentfulからデータを取得できるように設定を追加する
- Contentfulの管理コンソールで`Settings`->`API keys`からAPIキーを取得する
<img width="359" alt="スクリーンショット 2019-09-06 18.53.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/d7e1878a-5f20-5300-1f75-2ffb14cfea78.png">

- `Example Key 1`が事前に作られてるのでそれを選択
<img width="500" alt="スクリーンショット 2019-09-06 18.55.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/709dbaea-0544-af59-ed5d-a8584f7ba80b.png">

- `Space ID`と`Content Delivery API - access token`をこの後使うので控えておく
<img width="454" alt="スクリーンショット 2019-09-06 18.56.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/2b1545fa-a159-edcf-b6b7-40528485795c.png">

#### アプリにContentfulの設定を追加

- GatsbyのContentfulプラグインを追加

```bash
# gatsby-sampleディレクトリ内で実行
npm install --save gatsby-source-contentfule
```

- アプリのプロジェクト直下に`.env`というファイルを作成する
<img width="268" alt="スクリーンショット 2019-09-06 19.02.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/674b49a2-206e-2bb1-b959-5675254bdb4e.png">

- 上の作業で控えた`Space ID`と`Content Delivery API - access token`を設定する
<img width="406" alt="スクリーンショット 2019-09-06 19.12.53.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/4d6991bc-847b-995d-843e-0cf4079bb269.png">

- `gatsby-config.js`を修正する

```js
// ファイルの先頭に以下の内容を追加
const dotenv = require("dotenv")

if (process.env.ENVIRONMENT !== "production") {
  dotenv.config()
}


// 下から3行目に以下の内容を追加
    {
      resolve: "gatsby-source-contentful",
      options: {
        spaceId: process.env.spaceId,
        accessToken: process.env.accessToken,
      },
    },
```

- 左に緑の線がついている行が追加したところ
<img width="550" alt="スクリーンショット 2019-09-06 19.16.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/5eb3bfc2-8284-c225-06fd-2e568809215d.png">

- `src/pages/index.js`を以下のように修正する

```jsx
import React from "react"
// importを追記
import { useStaticQuery, graphql, Link } from "gatsby"

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

const IndexPage = () => {
  // queryの取得処理を追加
  const data = useStaticQuery(graphql`
    query allContentfulUser {
      allContentfulUser {
        nodes {
          id
          name
          age
        }
      }
    }
  `)
  return (
    <Layout>
      <SEO title="Home" />
      <h1>Hi people</h1>
      {/* 取得したデータを表示する処理を追加 */}
      {data.allContentfulUser.nodes.map(({ id, name, age }) => (
        <h3 key={id}>
          {name}({age}歳)
        </h3>
      ))}
      <p>Welcome to your new Gatsby site.</p>
      <p>Now go build something great.</p>
      <div style={{ maxWidth: `300px`, marginBottom: `1.45rem` }}>
        <Image />
      </div>
      <Link to="/page-2/">Go to page 2</Link>
    </Layout>
  )
}

export default IndexPage
```

#### Contentfulから取得したデータをアプリで表示する

- ここまでの設定が終わったらアプリを起動する

```bash
npm start
```

- 以下のようにContentfulに登録したデータが表示される
<img width="404" alt="スクリーンショット 2019-09-06 19.29.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/167dd838-e897-74b1-c477-2f7bc7a21387.png">

- ※アプリを起動しようとすると実行ログの途中でとまってしまい処理が進まなくなることがあった
    - その時はContentfulの管理コンソールの`Media`に適当な画像をアップロードすると解消された(謎)


#### Contentfulから取得できるQueryの確認

- アプリを起動した状態で以下のURLにアクセスするとGraphQLのPlaygroundが表示される
    - http://localhost:8000/___graphql
<img width="902" alt="スクリーンショット 2019-09-06 19.31.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/8db75649-64b4-6cc9-125e-016cb4d196be.png">

- どのようなQueryがたたけるかここで試してから実装すると効率がよさそう
    - 今回は上のコードで`allContentfulUser`を使った

### Netlifyでホスティング

#### GithubへPushする

- ここまで開発したアプリをGithubにPushする
- リポジトリの作成手順やPush手順は割愛

#### NetlifyとGithubのリポジトリ連携

- `New site from Git`を選択
<img width="600" alt="スクリーンショット 2019-09-06 19.43.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/8fe82c9b-23ae-a9b1-5263-98b10c43d75f.png">

- Githubを選択しNetlifyからのアクセスを許可する
<img width="600" alt="スクリーンショット 2019-09-06 19.43.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/e0667911-491e-e745-6276-7d3ccc1816c6.png">

- アプリをPushしたリポジトリを検索し選択する
<img width="600" alt="スクリーンショット 2019-09-06 19.44.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/d5a3a281-30b1-6cd9-6b3f-addf77bc64a9.png">

- `Show advanced`から`New variable`を選択
<img width="600" alt="スクリーンショット 2019-09-06 19.46.24.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/c10ae98f-f373-c702-8c8b-6c55b33e3196.png">
<img width="600" alt="スクリーンショット 2019-09-06 19.46.53.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/6e078503-9224-018c-f1ba-088c158dde3a.png">

- `.env`に記載した項目2つと同じ値を設定し`Deploy site`を選択
<img width="550" alt="スクリーンショット 2019-09-06 19.48.03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/abf8add3-0eef-7633-b154-3158408269fb.png">

#### ホスティングしたページにアクセス

- デプロイ直後は以下のように`Site deploy in progress`と表示される
<img width="400" alt="スクリーンショット 2019-09-06 19.48.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/7890edbd-7f74-1162-7d72-a27c3d0989d8.png">

- デプロイが完了するとURLが表示されアクセスするとアプリにアクセスできる
<img width="400" alt="スクリーンショット 2019-09-06 19.51.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/b9d8d1c8-9c7e-cc05-f734-aefed58a579f.png">

#### Contentfulの更新をトリガーにでプロイできるようにする

- Netlifyの管理画面で`Settings` -> `Build & Deploy` -> `Build hooks`の`Add build hook`を選択
<img width="600" alt="スクリーンショット 2019-09-06 19.52.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/a3694fcb-e5be-322e-354e-5f04f13e4168.png">

- 適当な名前をつけて`Save`し保存後に表示されるURLを控えておく
<img width="433" alt="スクリーンショット 2019-09-06 19.54.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/3e30bfdf-4303-a984-447b-1cf0cf4176d2.png">

- Contentfulの管理画面で`Settings` -> `Webhooks`を選択
<img width="350" alt="スクリーンショット 2019-09-06 19.55.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/b14d92cc-729d-abc1-6784-2e25da3df4cb.png">

- Netlifyのアイコン横の`add`を選択し控えておいたURLを入力しCreateする
<img width="259" alt="スクリーンショット 2019-09-06 19.56.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/5ba6b544-20e3-ae96-0cc4-4c0a326f8ffc.png">
<img width="600" alt="スクリーンショット 2019-09-06 19.56.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/fe2b42dd-40b1-88c5-3237-0fcfb6f74f62.png">

- ここまでできると冒頭の説明のようにContentfulのデータを更新するとNetlifyのbuild/deployが走りWebページが最新化されるようになった！