M1 MacでDocker上にGatsby.jsの開発環境を作成して実行する(gatsby develop ,build, serve)

# 環境
- macOS Monterey 12. 0 .1
- Docker 20.10.13
- docker-compose version 1.29.2
- Gatsby.js 4.20.0

# ゴール
1. Gatsby.js(`Gatsby CLI`)が動作する環境をDockerコンテナ上に構築
1. Gatsby.jsのプロジェクトを作成する
    - `gatsby new`
1. Gatsby.jsのプロジェクトを実行する
    - `gatsby develop`
    - `gatsby build`
    - `gatsby serve`
1. Gatsby.jsのプロジェクトの構成を簡単に理解する


# 参考
- 開発環境の構築・実行
    - [公式のチュートリアルの開発環境の構築](https://www.gatsbyjs.com/docs/tutorial/part-0/)
    - [公式のチュートリアルのGatsbyサイトの作成とデプロイ](https://www.gatsbyjs.com/docs/tutorial/part-1/)
    
- Gatsby.jsプロジェクトの理解

https://qiita.com/kikuchi_kentaro/items/985b182a78c3553981ee#-lifecycle


# ディレクトリ構成

```bash
.
├── Dockerfile
├── docker-compose.yml
└── gatsby-my-site       // Gatsbyプロジェクト
    └── node_modules　とか色々..
```


# 環境構築

## Gatsby.jsをインストールしたDocker環境を作成
`docker-compose.yml`と`Dockerfile`を作成する

```bash
$ touch docker-compose.yml 
$ touch Dockerfile
```

### Dockerfile

Node.jsとGatsby.jsがインストールされた環境を作成する

```dockerfile:Dockerfile
FROM node:16-alpine
RUN apk update && apk upgrade && \
    apk add --no-cache bash git yarn python3 make g++  && \
    yarn global add gatsby-cli
EXPOSE 8000 9000
```

- `FROM` : imageは[docker hub](https://hub.docker.com/_/node)から取得
    <選定基準>
     - Node.jsがインストール済
     - M1 Mac対応
     - 軽量でdockerイメージのビルドが速いalpine linux
       ※dockerイメージについては、勉強中の身なので、拘って選んだとかではない
- `RUN` 
    - １行目：　apkコマンドのupdateとupgrade
    - ２行目：　必要ライブラリ等のインストール
        イメージの軽量化のため、`--no-cache`オプションを使ってインストール後に不要なファイルを削除する。
        - `bash`は好み
        - `git` `yarn` `python3` `make` `g++`はGatsby CLIのインストールやGatsbyプロジェクト作成時に必要
    - 3行目： `Gatsby CLI` をインストール
- `EXPOSE`
    ホスト(PC)からDockerコンテナ上で起動したGatsbyのサイトにアクセスするためポートを解放
        - 開発モード (gatsby develop デフォルトポート8000)
        - サーバ起動 (gatsby serve デフォルトポート9000)
  

### docker-compose.yml

Dockerfileを実行する設定を記載

```dockerfile:docker-compose.yml
version: "3.7"
services:
  gatsby-my-site:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: gatsby-my-site
    ports:
      - "8000:8000"
      - "9000:9000"
    volumes:
      - .:/app
    working_dir: /app
    stdin_open: true
    environment:
      - NODE_ENV=development
```
- `build` : Dockerfileの内容でイメージをビルドする
- `container_name` : 起動した時のコンテナ名を指定(任意の名前)
- `ports` : ホスト(PC)からDockerコンテナ上で起動したGatsbyのサイトにアクセスするため、ホストのportとコンテナのポートを紐付け
- `volumes` : 開発しやすいようにVolumeマウントでローカルのカレントディレクトリとDockerの「/app」を同期させる
- `working_dir` : Dockerコンテナ起動時の作業ディレクトリを指定
- `stdin_open` : trueでコンテナを起動し続ける
- `environment` : Node.jsの環境変数を設定


## Dockerコンテナ起動
`docker-compose.yml`がある場所で下記コマンドを実行する

```bash
$ docker-compose up -d
```

### 【確認】
コンテナに入って`Gatsby CLI`が実行できるか確認する

```bash
# コンテナに入る
$ docker exec -it gatsby-my-site /bin/bash 

# Gatsby CLIのバージョン確認
$ gatsby --v
╔════════════════════════════════════════════════════════════════════════╗
║                                                                        ║
║   Gatsby collects anonymous usage analytics                            ║
║   to help improve Gatsby for all users.                                ║
║                                                                        ║
║   If you'd like to opt-out, you can use `gatsby telemetry --disable`   ║
║   To learn more, checkout https://gatsby.dev/telemetry                 ║
║                                                                        ║
╚════════════════════════════════════════════════════════════════════════╝
Gatsby CLI version: 4.20.0
```
成功！！！！


# Gatsby.jsのプロジェクトを作成＆実行

以下作業をDockerコンテナに入って実行する。　(作業ディレクトリ「/app」で実施)


## プロジェクト作成
`gatsby new {project-name} {starter-url}`コマンドで作成できる

- `project-name`   プロジェクト名
- `starter-url` 使いたいスターターのURL

:::note info 
スターターとはgatsbyプロジェクトのテンプレートのことで公式サイトの「[Starter Library](https://www.gatsbyjs.com/starters/?v=2)」で提供されている。
:::


### 実行

```bash
$ gatsby new my-gatsby-site https://github.com/gatsbyjs/gatsby-starter-hello-world
```


## 開発モードで実行する(`gatsby develop`)

`gatsby develop`で、作成したプロジェクトをビルドして開発サーバを起動する
dockerコンテナ内のページをホスト(PC)から確認できるように、IPアドレスを`0.0.0.0`を指定する

```bash
# プロジェクトに移動
$ cd my-gatsby-site 

# 開発モードで起動
$ gatsby develop --host=0.0.0.0

⠀
You can now view gatsby-starter-hello-world in the browser.
⠀
  Local:            http://localhost:8000/
  On Your Network:  http://XXX.XX.X.X:8000/
⠀
View GraphiQL, an in-browser IDE, to explore your site's data and schema
⠀
  Local:            http://localhost:8000/___graphql
  On Your Network:  http://XXX.XX.X.X:8000/___graphql
```

起動後、`http://localhost:8000` にアクセスするとサイトが表示される！

:::note info 
`--host=0.0.0.0`オプションを指定して Gatsby 開発コマンドを実行すると同じネットワーク上の他のデバイスの開発環境にアクセスすることができる
（IPアドレスを`0.0.0.0`にすると無効なアドレスで、PCが自動で同じネットワークにするとかなんとか。ここでは詳細は記載しない）
:::


## ビルドとサーバ起動(`gatsby build` `gatsby serve`)

```
# プロジェクトに移動
$ cd my-gatsby-site 

# ビルド
$ gatsby build

# サーバー起動してビルドした結果を実行
$ gatsby serve --host=0.0.0.0
⠀
You can now view gatsby-starter-hello-world in the browser.
⠀
  Local:            http://localhost:9000/
  On Your Network:  http://XXX.XX.X.X:9000/
```

起動後、`http://localhost:9000` にアクセスするとサイトが表示される


# Gatsby.jsのプロジェクト構成とライフサイクル

## プロジェクト構成

作成したプロジェクトのファイル構成
(スターターは「https://github.com/gatsbyjs/gatsby-starter-hello-world」)


```
. my-gatsby-site
    ├── LICENSE
    ├── README.md
    ├── gatsby-config.js  # Gatsbyの設定ファイル(利用するプラグインの設定など)
    ├── node_modules
    ├── package-lock.json
    ├── package.json
    ├── public            # 公開ディレクトリ(ビルドして作成されたHTMLなどが格納される)
    ├── src               # ソースコード
    │   └── pages         # ページを構成するソースコード(URLに対応するReactコンポーネントを作成する)
    │       └── index.js
    └── static            # 画像やfaviconなど静的ファイル
        └── favicon.ico
```

- `TypeScript`にも対応しているので、プラグイン追加や設定を行えば`TypeScript`で記載することができる
- プラグインやサイト全体の設定を行うには、プロジェクトルートに手動で以下のファイルを作成して設定のコードを記載する
    - gatsby-node.js
    - gatsby-ssr.js
    - gatsby-browser.js

### gatsby-node.js
- ビルド時の処理について記載する
- このファイルにあるコードは、ビルドの時に一度だけ実行される
- [Gatsby Node APIs](https://www.gatsbyjs.com/docs/reference/config-files/gatsby-node/) を使って、ページを動的に作成やwebpack設定を拡張/変更させることなどできる
    - `gatsby develop`と`gatsby build`のどちらからも実行されるAPI
        - [onPreBootstrap](https://www.gatsbyjs.com/docs/reference/config-files/gatsby-node/#onPreBootstrap)　bootstrap-sequence 開始直前に実行
        - [onPostBootstrap](https://www.gatsbyjs.com/docs/reference/config-files/gatsby-node/#onPostBootstrap)　bootstrap-sequence 終了直前に実行
    - `gatsby build`から実行されるAPI
        - [onPreBuild](https://www.gatsbyjs.com/docs/reference/config-files/gatsby-node/#onPreBuild)　 　ビルド開始直前に実行
        - [onPostBuild](https://www.gatsbyjs.com/docs/reference/config-files/gatsby-node/#onPostBootstrap)　　ビルド終了直前（全プロセス完了後）に実行

>`bootstrap-sequence`はビルドのメイン処理(のようである)　
> [公式サイトドキュメント](https://www.gatsbyjs.com/docs/conceptual/gatsby-lifecycle-apis/)
> すごくざっくり書くと
>  - `bootstrap-sequence`は、build後のソースだと`node_modules/gatsby/dist/bootstrap/index.js`　
      開始・終了時に[onPreBootstrap](https://www.gatsbyjs.com/docs/reference/config-files/gatsby-node/#onPreBootstrap)や[onPostBootstrap](https://www.gatsbyjs.com/docs/reference/config-files/gatsby-node/#onPostBootstrap)を実行している。
>  - コマンドはbuild後のファイルだと、`node_modules/gatsby/dist/commands`以下にあるコード
>     - `gatsby develop` は `develop.js`で、bootstrap-sequenceを実行している
>     - `gatsby build` は `build.js`で、bootstrap-sequenceの後に[onPostBootstrap](https://www.gatsbyjs.com/docs/reference/config-files/gatsby-node/#onPostBootstrap)と[onPostBuild](https://www.gatsbyjs.com/docs/reference/config-files/gatsby-node/#onPostBootstrap)を実行している

### gatsby-ssr.js
- サーバサイドレンダリング (SSR) される静的 HTML ファイルのコンテンツを変更するためのファイル
- [Gatsby SSR APIs](https://www.gatsbyjs.com/docs/reference/config-files/gatsby-ssr/) を使う

### gatsby-browser.js 
- webブラウザで表示される際の処理を実装するためのファイル
- [Gatsby Browser APIs](https://www.gatsbyjs.com/docs/reference/config-files/gatsby-browser/)を使う


# ライフサイクル
公式サイトに実行される内容が書かれていて、参考にしやすかった（まだ記載途中ぽいが）

https://www.gatsbyjs.com/docs/conceptual/gatsby-lifecycle-apis/


こちらの記事がとてもわかりやすく、おかげで概要が理解できました！

https://qiita.com/kikuchi_kentaro/items/985b182a78c3553981ee#-lifecycle


# おわりに
Gatsby.jsの各バージョンでのサイト構築を勉強したく、ローカルを汚さず手軽に勉強できる環境を作りたいなと思いやってみました。
日本語不自由なので記事を書くのは悩みましたが、思い切って投稿しました！
Gatsby.jsとDockerについて勉強中なので、ご指摘・ご意見があればコメントいただけますとありがたいです。