Next.js + microCMS + NetlifyでJAMstackな世界に入門する

# 追記:
Next.js v9.3以降SSGに関するAPIの変更や、環境変数の扱い方が変わったので、対応した記事に書き換えました。

# はじめに
この記事は[JAMstack Advent Calendar 2019](https://qiita.com/advent-calendar/2019/jamstack) 7日目の記事です。

こんにちはかみむらです。最近は、[Twitter](https://twitter.com/kamimura_th)上でJAMstackアーキテクチャーについての情報をシェアしています。

先日、個人のポートフォリオをJAMstackアーキテクチャーな構成で立ち上げました。このサイトの技術スタックは**Next.js(静的サイト) + microCMS**でホスティングサービスに**Netlify**を利用しています。

JAMstackは静的なJavaScript、独立したAPI、ビルド済みのマークアップを総称したアーキテクチャーで、今回作成したウェブサイトはこれらの要件を満たしていることになります。もしJAMstackアーキテクチャーをもっと詳しく知りたい場合は、こちらの公式サイトをご参照ください。
https://jamstack.org/

そして、Googleが公式で開発しているウェブサービスの品質を測定できるツール「Lighthouse」でポートフォリオの数値を測定した結果がこちらです。環境で多少の誤差はありますが、非常にハイパフォーマンスな数値が出ています。

![Screenshot from 2019-12-06 12-16-57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406132/e753ce56-fd66-0c76-30f7-44d841cdc14d.png)

JAMstackアーキテクチャーでウェブを構成する利点の一つに、**JavaScript(フロントエンド)に重点を置ける**ことがあります。ヘッドレスCMSのmicroCMSやNetlifyの登場で、今までサーバーにかけていた工数が大幅に減るので、その分**パフォーマンスチューニング**や**UX向上**に時間をかけることが出来ます。そして、フロントエンドに注力できることはフロントエンドの開発者にとってDXを高めることに繋がります。

# デモ
こちらにNext.js + microCMSのデモコードがあります。
https://github.com/hiro08gh/next-microcms-ssg

# 今回作るJAMstackなサイトの全体像
上記で説明した技術スタックを使っていきます。フロントエンドは**Next.js**で構成して、apiを**microCMS**でコンテンツ管理をします。microCMSとは日本製のヘッドレスCMSで、リクエストヘッダーにapiキーを含めて送ることで、データを取得することができます。そして、Next.jsで生成する静的なファイルを**Netlify**でホスティングします。

# microCMSのコンテンツモデル作成
![スクリーンショット 2019-12-05 17.43.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406132/1ed70119-eba8-bd49-7db4-21af20c5c322.png)

まずはmicroCMSでコンテンツモデルを作成します。下記のリンクからアカウント作成を行ってください。
https://microcms.io/

作成するコンテンツモデルは簡易的なブログを想定しています。

**blogs**というモデルに対して、**tags**というモデルがリレーションされています。そして、**blogs**は**tags**を複数持つことが出来ます。それでは早速作っていきましょう。

アカウント作成後、**サービス名**と**サービスID**を入力します。**サービスID**はエンドポイントのドメインになるので、関連するワードにしたほうがいいかもしれません。

![スクリーンショット 2019-12-04 21.11.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406132/51f2636f-c8b0-ec08-2579-bbf259fc2550.png)

ステップ２のサービス画像は後から設定できるのでスキップでも大丈夫です。

それではコンテンツを作成していきます。まずは**タグ**のコンテンツモデルから作成します。APIの名前とエンドポイントを入力します。ここでは**タグ**と**tags**を入力しました。

![スクリーンショット 2019-12-04 21.19.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406132/45b191db-46cf-7f06-f9c9-f3b78dc5bb2d.png)


そしてapiの型を設定します。こちらは**リスト形式**にします。

![スクリーンショット 2019-12-05 21.03.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406132/5c23c097-0217-50b2-5d33-e3114f335635.png)

APIスキーマを定義します。タグは**name**のスキーマを一つ持っています。

![スクリーンショット 2019-12-05 21.05.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406132/010cdf46-b9b6-f3fe-c6e1-2f765c3b456e.png)

続いてブログのコンテンツモデルを作成します。API名は**ブログ**でエンドポイントは**blogs**にしました。

![スクリーンショット 2019-12-05 21.06.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406132/1554bf05-c023-2311-7938-f229d15e7bf2.png)

こちらも続いてリスト形式にします。
![スクリーンショット 2019-12-05 21.03.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406132/5c23c097-0217-50b2-5d33-e3114f335635.png)

ブログのコンテンツモデルはこちらです。**タグ**のスキーマを**複数コンテンツ参照**にします。これで**ブログ**と**タグ**のリレーションを作ることができました。

![スクリーンショット 2019-12-07 7.37.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406132/cc97c1bc-9528-70b7-63b4-142b9ec73024.png)

microCMSのコンテンツモデルができました。フロント側で取得するために、いくつかコンテンツを作成してみましょう。

サイドバーにある**タグ**をクリックして、**追加**をクリックします。

![スクリーンショット 2019-12-05 21.14.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406132/86c32d21-a25f-c1dc-cb1e-fd6f45c033d8.png)

**タグ名**を入力します。入力値はなんでも大丈夫です。そして**公開**します。
![スクリーンショット 2019-12-05 21.14.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406132/deaaf502-e853-8f41-e046-8a3ad5f2eb9a.png)

**ブログ**のコンテンツも作成します。
![スクリーンショット 2019-12-07 7.32.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406132/5bd0121d-53ca-1991-9e1f-6990d9893bf1.png)

これでリレーションを含むコンテンツを作成出来てしまいました。microCMSは導入障壁が非常に低いので、最高ですね。

# Next.jsプロジェクトの作成
次にJAMstackのJ(JavaScript)部分を構築していきます。create-next-appという便利なCLIライブラリがあるので、これでプロジェクトの雛形を作っていきます。

```console
$ npx create-next-app my-app
```

Default Starter appを選択してプロジェクトを作成してください。

![スクリーンショット 2020-05-19 10.00.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406132/a4c62e2e-547d-d1d2-f60c-300425f5bc91.png)

microCMSではリクエストヘッダーにapiキーを含めてリクエストを送ります。セキュリティー確保のため、apiキーは`.env`ファイルに保存する必要があります。

そして```.env.development.local```ファイルを作成して、microCMSのAPIキーを追加します。**XXXXXX**の部分を置き換えてください。APIキーはmicroCMSの設定から取得することが出来ます。

![スクリーンショット 2019-12-05 21.22.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406132/16f44e71-b77b-5057-4398-42e0c694473e.png)


```bash:.env.development.local
API_KEY=XXXXXXXXXXXXXXXX
```

これでプロジェクトのセットアップは完了です。

# microCMSからデータを取ってくる処理
microCMSのコンテンツデータを取得します。フロントエンド側で取得するため、isomorphic-unfetchをインストールします。

```console
$ yarn add isomorphic-unfetch
```

追記: isomorphic-unfetchは必要なくなりました。データ取得はfetch apiですることができます。

そして、pagesフォルダにあるindex.jsの内容を書き換えます。`https://your.microcms.io/api/v1/blogs/`には先ほど作成したmicroCMSのURLを入れます。

```jsx:index.js
import fetch from 'isomorphic-unfetch';
import Link from 'next/link';

const Home = ({blogs}) => {
  return (
    <div>
      <h2>最新の記事</h2>
      <div>
        {blogs.map(blog => (
          <React.Fragment key={blog.id}>
            <Link href="/blogs/[id]" as={`blogs/${blog.id}`}>
              <a>
                <h2>{blog.title}</h2>
              </a>
            </Link>
            {blog.tags.map(tag => (
              <React.Fragment key={tag.id}>
                <span>{tag.name}</span>
              </React.Fragment>
            ))}
          </React.Fragment>
        ))}
      </div>
    </div>
  );
};

export const getStaticProps = async () => {
  const key = {
    headers: {'X-API-KEY': process.env.API_KEY},
  };
  const res = await fetch(
    `https://your.microcms.io/api/v1/blogs/`,
    key,
  );
  const data = await res.json();
  
  return {
    props: {
      blogs: data.contents,
    }
  }
};

export default Home;
```

ここでは`getStaticProps`という静的なメソッドを使って、ページを読み込む前にデータを取得してます。なので、取得したデータを元に静的なHTMLを生成することできます。

そしてLinkの`href`でルートの遷移先をしていします。blogsが持っているidを元にします。ダイナミックルーティングをする場合、Linkに```as```を指定する必要があります。これは、ブラウザのURLバーに表示されるパスです。

# 個別ページの作成

記事のリストページができました。次に記事の個別ページを作成していきます。microCMSでapiのプレビューをすることが出来ます。
![Screenshot from 2019-12-06 19-37-35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406132/89844110-8a67-94a5-e261-346d82123b76.png)

pagesフォルダの中に**blogs**フォルダを作成してその中に**[id].js**を作成します。
/blogs/[id].js

```jsx:[id].js
import fetch from 'isomorphic-unfetch';

const BlogId = ({blog}) => {
  return (
    <div>
      <h1>{blog.title}</h1>
      <div>
        {blog.tags.map(tag => (
          <React.Fragment key={tag.id}>
            <span>{tag.name}</span>
          </React.Fragment>
        ))}
      </div>
      <div dangerouslySetInnerHTML={{__html: `${blog.body}`}}></div>
    </div>
  );
};

export const getStaticPaths = async () => {
  const key = {
    headers: {'X-API-KEY': process.env.API_KEY},
  };

  const res = await fetch('https://your.microcms.io/api/v1/blogs', key);
  const repos = await res.json();

  const paths = repos.contents.map(repo => `/blogs/${repo.id}`); 
    return {paths, fallback: false};
  };

export const getStaticProps = async context => {
  const id = context.params.id;

  const key = {
    headers: {'X-API-KEY': process.env.API_KEY},
  };

  const res = await fetch(
    `https://your.microcms.io/api/v1/blogs/${id}`,
    key,
  );
  const blog = await res.json();

  return {
    props : {
      blog: blog,
    }
  };
};

export default BlogId;
```

先ほどとは違って、**getStaticPaths**が登場しました。これは、Dynamic Routeの際にページ毎に静的なHTMLを生成するAPIです。ここでは、microCMSの個別ブログのデータを取得して静的なHTMLを生成しています。

ここでは`context.query`でid情報を取得しています。取得したid情報を元に、microCMSから個々のデータを取り出します。

一度これを実行してみましょう。

```console
$ yarn dev
```
![スクリーンショット 2019-12-06 20.28.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406132/481d902b-9f69-382f-25cb-cd96026961db.png)


そして個別ページも取得することができました。

![スクリーンショット 2019-12-06 20.29.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406132/c78b1a68-cfaf-5ef8-ec32-dc06da35df45.png)

microCMSで作成したデータのリストと個別のデータを取得することができました。スタイルを整えればブログになりますね。

# Next.jsのビルド設定

簡易的ではありますが、microCMSでコンテンツを管理できるブログが作成できました。

Next.jsでは静的なHTMLをexportするためのコマンド`next export`があります。これを実行すると、`out`というフォルダが生成されます。package.jsonに追加しましょう。

```json:package.json
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    //追記
    "export": "yarn run build && next export" 
  },

```

これで一通りできました。ちゃんとできるか試しにローカルでビルドしてみましょう。まずは、ローカルでビルドするためのenvファイルを作成します。内容は先ほどと同じです。

```bash:.env.local

API_KEY=XXXXXXXXXXXXXXXX
```

```console
$ yarn export
```

すると、フォルダ内にoutが作成されました。
![Screenshot from 2019-12-05 20-06-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406132/02c547d2-0b7c-da6e-bb92-6574b374e0ab.png)


ここからはNetlifyとGitHubを連携する必要があるので、レポジトリを作って、ソースコードをプッシュしてください。

# Netlifyにビルドする

![スクリーンショット 2019-12-05 20.41.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406132/9ab86f2c-ba23-cd3c-9992-e3bceae36721.png)

https://www.netlify.com/

ビルドするための設定します。
アカウントを認証後、ダッシュボードの**New site from Git**をクリックします。
![スクリーンショット 2019-12-05 20.46.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406132/92d605ab-b2f4-7e0c-6413-c9c7850df552.png)

今回はGitHub上にソースコードをあげたので、GitHubを選択します。すると、認証を求められます。
![スクリーンショット 2019-12-05 20.47.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406132/43e27fba-a256-ef61-ad9d-3facd7e217b0.png)

認証に成功すると、自分のレポジトリからどのレポジトリをホスティングするか選択する必要があります。**自分がプッシュしたプロジェクト**を選択しましょう。

![スクリーンショット 2019-12-05 20.49.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406132/4406fd2f-5e68-6996-2235-9302a2e2c8de.png)

静的ファイルをビルドするコマンドとディレクトリーを指定します。これは先ほど確認したものです。

![Screenshot from 2019-12-04 22-53-36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406132/f93b91bc-ee0a-7642-0896-4da1899c7db8.png)


### Netlifyで環境変数を設定する
**Advanced build settings**から環境変数を設定します。ここでは.envファイルに入れた、microCMSのapiキーを指定します。これで**Deploy site**をしてみましょう。

![Screenshot from 2019-12-04 22-50-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406132/e3e95c2a-b0a8-d7db-359c-6509fc9b2e88.png)

無事ビルドが完了して、デプロイされるとURLが発行されます。
![スクリーンショット 2019-12-06 20.36.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406132/6a682f24-3de4-5ed0-f1d2-b247facdfa97.png)

ローカルで確認して内容が確認できます。これでJAMstackなサイトを作る第一歩として一連の流れが終わりました。

![スクリーンショット 2019-12-06 20.37.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406132/6fa81310-7042-f194-37e3-8f22bcbef298.png)

# 最後に
今回はJAMstackアーキテクチャーの導入部分として、簡易的なブログを作成しました。microCMSは無料枠の範囲が非常に広いので、試しに使ってみてください。