Jamstack な構成（Gatsby+microCMS+Firebase）で個人サイトを作成しました

今年の GW もステイホーム期間でしたので、フロントエンド周りの技術勉強も兼ねて個人サイトを作成してみました。
折しも、 Qiita では「フロントエンド強化月間」となっていましたので、記事にします。

https://qiita.com/official-events/b9ad63394fa2635dfca9

# 完成したサイト

- まだ未完成な部分はありますが、 https://www.zakioka.net/ で個人サイトを公開しました。
- ソースは GitHub のリポジトリに公開しております：

https://github.com/tsuchinoko0402/website

- 大まかな構成は以下のとおりです：
    - いわゆる Jamstack な構成にしています。
        - 「J」と「M」：Gatsby
        - 「A」：microCMS
        - ビルドとデプロイ：GitHub Actions
        - ホスティング： Firebase Hositing

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/753251/c25582bf-6898-a642-6080-ee91751a5507.png)

- 個人サイトで実現した機能は以下のとおりです：
    - 個人のプロフィール表示
    - Markdown で記述した技術メモを Web ページとして公開
    - microCMS でブログ記事を作成し、それを Web ページとして公開
    - Qiita と note に投稿した記事の一覧ページ
- Qiita や note よりも気軽なアウトプットの手段が欲しかったというのもあります。
- Jamstack な構成であれば、 Gatsby + GitHub + Netlify な構成がメジャーのように見えたのですが、色々と比較してみた結果、この構成が自分には使いやすそうということで、この構成にしました。

# 利用技術・サービス概要

## Jamstack

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/753251/322f9b2c-f4c9-3903-9dc6-01935ad1c8d9.png)

- [公式サイト](https://jamstack.org/)
- CDN（Content Delivery Network）から直接サービスを提供できるサイトを構築するための新しいアーキテクチャ
    - JavaScript、API、および事前にレンダリングされたMarkupの略
    - サーバーとフロントエンドを疎結合にし、サーバーが担っていた機能を外部化してフロントだけで扱いやすくする構成
- 一般的な Web アプリと違い、静的なコンテンツを配信するだけ
- 動的なデータはビルド時に取得する
    - ビルドして HTML を生成する際に API からデータを取得して埋め込む
    - データが更新されたタイミングで都度ビルドとデプロイを行う

## Gatsby

- [公式サイト](https://www.gatsbyjs.com/)
- [React](https://ja.reactjs.org/) ベースの静的サイトジェネレータ（SSG）
- 各種データソースからコンテンツを取得する方法として [GraphQL](https://graphql.org/) が標準で利用可能
- プラグインが豊富なため、効率的に Web サイトの機能を追加することが可能
    - スターターテーマも充実しているため、サクッとそれっぽいサイトを立ち上げることも可能
    - SEO 対策も実装されている

## microCMS

- [公式サイト](https://microcms.io/)
- 日本製のヘッドレス CMS
    - ヘッドレス CMS は従来の CMS（WordPress、 Qiita、note 等）と比較して、ビューに当たる部分が無い
        - 入稿したコンテンツは API 経由で取得する
- 個人サイトレベルであれば無料で利用可能
- 非技術者でも管理画面がわかりやすい UI となっている。
- [ドキュメント](https://document.microcms.io/)も充実
- Gatsby での利用にあたっては、[公式でプラグイン](https://www.gatsbyjs.com/plugins/gatsby-source-microcms/)が用意されている

## GitHub Actions

- [公式サイト](https://github.co.jp/features/actions)
- GitHub だけで CI/CD 的な機能を実現できる機能
- 操作（リポジトリに対するプッシュやプルリクエスト等）やイベント（指定した時刻になる等）をトリガーとして、あらかじめ定義しておいた処理を実行する
- 今回は、GitHub のリポジトリへの Push（Gatsby で作成したサイトのソースや Markdown で書いた内容の更新）されたときと microCMS でブログの内容更新を契機とした Webhook を受けたときをトリガーとして、ビルドとデプロイを実行する

## Firebase Hosting

- [公式サイト](https://firebase.google.com/?hl=ja)
- Firebase はGoogle が提供しているモバイルおよび Web アプリケーションのバックエンドサービス
    - クラウドサービスの形態では mBaaS に位置付けされる
    - 2014年に Google に買収され、Google Cloud Platform(GCP) の仲間入り
    - 現在は GCP の様々なサービスと連携して使うことができる
- Firebase Hosting は静的な Web ページを公開することができる機能
- 無料の Spark プランが用意されている
    - 個人サイトレベルではこれで十分
    - 万が一、超過してしまっても勝手に課金されることはない
    - 今回は、ビルド済みの静的サイトをホスティングして Web サイトを表示するために利用する

# サイト作成〜公開までの大きな流れ

## React と Gatsby のチュートリアルで概要を知る

- いずれも公式のドキュメントが非常に充実していたので非常に助かりました。
- 細かい部分は一度ドキュメントを眺めただけでは理解しきれませんでしたが、以下の概要は掴んだつもりです。
    - React のコンポーネント、 `state` と `props` 、イベントハンドラ
    - Gatsby におけるデータの扱い（GraphQL）、動的ページの作成
    - React と Gatsby の TypeScript 化

https://ja.reactjs.org/tutorial/tutorial.html

https://www.gatsbyjs.com/docs/tutorial/

## 書籍で知識整理

- ↑のチュートリアルで概略は掴めましたが、知識を整理するために、以下の本を買って読んでなぞってみました。
    - [井手 優太「React環境構築の教科書」インプレスR&D(2020)](https://nextpublishing.jp/book/12108.html)
    - [竹本 雄貴「React & Gatsby開発入門」インプレスR&D(2021)](https://nextpublishing.jp/book/12958.html)
- 本を読むと、目標が明確になった気がします。

## Gatsby でコンテンツ作成

- 一番時間かかりましたが、やりたいことの実現に向けてガシガシコードを書いてました。
- 見た目等の UI 周りは [Material UI](https://material-ui.com/) を用いました。
    - またちょっと使いこなせてない感じがあるので追々勉強…
- 初っ端から TypeScript で書くことに決めていたので、その設定も行いました。
- 細々したことは自サイトのブログに書きました。
    - [Qiita や note に投稿した記事一覧を Gatsby で表示する](https://blog.microcms.io/getting-started/)
    - [Gatsby で GraphQL 実行結果の型を作成する](https://www.zakioka.net/blog/gatsby-plugin-typegen/)
    - [Gatsby で Markdown をコンテンツソースとして扱う](https://www.zakioka.net/blog/gatsby-md-content/)

## microCMS との連携

- 公式ドキュメントのチュートリアルに沿って設定ができました。

https://blog.microcms.io/getting-started/

https://document.microcms.io/tutorial/gatsby

### 必要な API の作成

- 今回はブログ機能を持たせるために、カテゴリ、タグ、ブログ記事の3つの API を作成しました。
    - カテゴリ：「技術記事」「ブログ」等、大まかな分類。1つの記事に対して1つしか付けられないようにする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/753251/6b6adea2-53e6-d4a7-31d7-a07b757e552d.png)

    - タグ：記事に付与する具体的な技術名等。1つの記事に対して複数付けられることを想定。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/753251/682bb2f2-52b1-53d3-9fb2-ec6bf9926e76.png)

    - ブログ記事：記事の内容。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/753251/d1f88b5b-baf7-8748-94ed-3e8dd4a234fe.png)

### Gatsby に microCMS の設定を記述する

- microCMS の API を利用するための API キーは サービス設定 > API-KEY から確認可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/753251/6bd847b3-4d85-4b0c-efb6-35246cfb3162.png)

- API キーをソースコードに含めないように、環境変数 `MICROCMS_API_KEY` に API キーを設定しておきます。また、自身で決めたサービス ID も環境変数 `MICROCMS_API_ID` に設定しておきます。
- Gatsby のプラグインをインストールして、プラグインの設定を `gatsby-config.js` に記述します。

```shell:gatsby-source-microcmsのインストール
$ yarn add gatsby-source-microcms
```

```js:gatsby-config.js
module.exports = {
 //...
  plugins: [
 //...
    {
      resolve: `gatsby-source-microcms`,
      options: {
        apiKey: process.env.MICROCMS_API_KEY,
        serviceId: process.env.MICROCMS_SERVICE_ID,
        apis: [
          {
            endpoint: "post",
          },
          {
            endpoint: "category",
          },
          {
            endpoint: "tag",
          },
        ],
      },
    },
 //...
  ],
}
```

### データを利用した動的ページの作成

- Gatsby プロジェクトに `src/pages/blog/{MicrocmsPost.slug}.tsx` を作成し、以下のような内容で作成することで、記事のページが作成できます。

```
import * as React from "react"
import { graphql, PageProps } from "gatsby"

const PostPage: React.FC<PageProps<GatsbyTypes.BlogPageQuery>> = ({ data }) => {
  const post = data.microcmsPost
  return (
    // 表示するページの内容
  )
}

export const query = graphql`
  query BlogPage($id: String!) {
    microcmsPost(id: { eq: $id }) {
      slug
      title
      content
      publishedAt(formatString: "YYYY.DD.MM hh:mm")
      updatedAt(formatString: "YYYY.DD.MM hh:mm")
      category {
        slug
        name
      }
    }
  }
`
```

- その他、やったことについては自サイトのブログに記載しました。
    - [microCMS に保存したコンテンツを Gatsby のページ上に表示する](https://www.zakioka.net/blog/gatsby-microcms/)

## Firebase へのデプロイと独自ドメインの設定

- Gatsby のプロジェクトに Firebase とツールを入れ、 Firebase Hosting を利用してデプロイしました。
- 取得していた独自ドメインの設定もしました。
- 詳細については、自サイトのブログに記載しました。
    - [Gatsby で作成したページを Firebase で公開する](https://www.zakioka.net/blog/gatsby-firebase-hosting/)

## GitHub Actions で自動デプロイの設定

- ソースの更新や microCMS のコンテンツを更新・公開を契機に自動でビルド＆デプロイが走るように GitHub Actions の設定を行いました。
- microCMS のコンテンツの公開・更新時に Webhook で GitHub に通知が行くように設定しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/753251/776303c5-6f00-671f-9c8c-ccdf822e4346.png)

https://blog.microcms.io/webhook-for-github-actions/

- GitLab CI/CD は触ったことがあるのですが、GitHub Actions は初めてでした。正直、↓のドキュメントの内容ほぼそのままです^^;

https://docs.github.com/ja/actions/guides/building-and-testing-nodejs

```yaml:.github/workflows/node.yml
name: Node.js CI

on:
  push:
    branches: [main]
  repository_dispatch:
    types: [update-posts]

jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [14.x]
    steps:
      - uses: actions/checkout@v2
      - uses: actions/cache@v2
        with:
          path: ~/.cache/yarn
          key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }}
          restore-keys: |
            ${{ runner.os }}-yarn-
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v1
        with:
          node-version: ${{ matrix.node-version }}
      - run: yarn install --frozen-lockfile
      - run: yarn build
        env:
          MICROCMS_API_KEY: ${{ secrets.MICROCMS_API_KEY }}
          MICROCMS_SERVICE_ID: ${{ secrets.MICROCMS_SERVICE_ID }}
      - if: github.ref == 'refs/heads/main'
        run: yarn firebase deploy --token $FIREBASE_TOKEN
        env:
          FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
```

- あと細々した話は、ブログの記事に記載しました。
    - [GitHub Actions を用いて Jamstack な構成の Web サイトを自動でデプロイする](https://www.zakioka.net/blog/github-actions-jamstack-deploy/)

# まとめ

- フロントエンド周りの技術はあまり馴染みがなかったので、改めていろいろと触れてみて勉強になりました。
- Jamstack という流行りのイケイケな概念に対しては敬遠していた部分もあったのですが、実際に手を動かしてみるとあっさり公開まで行けたなという感じです。
- Gatsby や Material UI を使いこなせていないので、サイトの見た目周りについては大幅に改善の余地がありそうだなと感じています。
    - Material UI 使ってるので、 [Material Design](https://material.io/) あたりは勉強したほうが良いかな、と思いつつ。
- 今後も、ちまちまとブログやメモを更新しつつ、以下のことに引き続き取り組んでいこうかなと思います。
    - デザインの細かい変更
        - ブログやメモのデザイン
        - フォントの変更
        - 色の変更
        - 見出しのデザイン
    - ブログやメモのカテゴリ、タグ機能
    - ブログの表示時間が変なので修正する
    - カテゴリやタグごとの一覧表示
    - データ部分と見た目に関する部分の分離
    - コンポーネントの上手い分割
    - ユニットテスト