Remote ContainersでReactのDocker開発環境を構築

# 概要

- 更新内容
  - ※emvファイルをdocker-compose内に変更しました。

- 環境
  - React
     - TypeScript
     - storybook
  - DockerImage
     - node:13.12.0-slim

- 開発環境は下記のリポジトリにあるのでお好きに使って下さい。
  - [react-docker-development-environment](https://github.com/I-s-23/react-docker-development-environment)
     - そのままpushをすると、私のリポジトリの内容が変更されてしまうので、pushとかは自分のリポジトリを作成して行って下さい。
     - 使用して気に入ったのなら☆を付けてくれると励みになります。


## 前提

- Docker
  - [いまさらだけどDockerに入門したので分かりやすくまとめてみた](https://qiita.com/gold-kou/items/44860fbda1a34a001fc1)
     - 自分はWSL2＋Docker for windowsで環境構築しました
         - [Windows環境のWSL2とDockerのある開発環境構築メモ2020/06](https://qiita.com/yoskeoka/items/2d019d92fe6931930271)
         
- Remote Containers
  - [VSCode Remote Containerが良い](https://qiita.com/d0ne1s/items/d2649801c6f804019db7)
     - この記事にDockerやRemote Containersで環境構築することの良さが書かれてます

- なぜDockerでReactの開発環境を作るのか
  - プロジェクトでnodeのバージョンなどを固定できる
  - ホストマシンにNodeを入れなくてOK
  - プロジェクトメンバーが増えてもコンテナを開くだけで環境構築が完了

- なぜRemote ContainersでReactの開発環境を作るのか
  - Remote Containersならコンテナを開くときに拡張機能をインストールしてくれるのでプロジェクトで環境を統一可能。
  - VSCodeの設定もプロジェクト単位で統一可能。(フォーマッターなど)
  - プロジェクトメンバーが増えてもコンテナを開くだけで環境構築が完了(超重要)

## 使い方

1. [react-docker-development-environment](https://github.com/I-s-23/react-docker-development-environment)を git clone
2. VSCodeの拡張機能でRemote Containersを追加する
3. VSCodeで「Ctrl + Shift + p 」と入力
4. Remote-Containers: Open Folder in Container と入力
5. プロジェクト配下のdockerという名前のフォルダを選択する(.devcontainer配下が展開される)
5. 実際に開発環境として使用する場合、ssh-agentを有効にしないとPushできません
    1. [VSCode Remote ContainersでGitにSSH接続でpushする (Windows)](https://wonwon-eater.com/vscode-remote-containers-git/)


## CreateReactApp

今回の環境はReactでTypeScriptを使用し、storybookの環境構築を済ませた環境になっております。
自分で環境構築を行う場合、以下の手順でできます。

1. Nodeを使用可能なコンテナを起動
   1. [Docker Hub - Node](https://hub.docker.com/_/node)
2. コンテナ内で以下のコマンドを実行

    ```Bash
    npm install -g create-react-app
    ## TypeScriptでReactのApplication構築を行う(テスト環境も配備)
    create-react-app sample --typescript
    cd sample
    # Reactのプロジェクトフォルダ配下で実行することでstorybookの環境構築を行う
    npx -p @storybook/cli sb init --type react_scripts
    ```

## 実装した内容

実際に環境変数で使用している内容の解説をします。

```Dockerfile:Dockerfile
# ベースとするDockerImage
FROM node:13.12.0-slim
WORKDIR /usr/app
# パッケージの依存関係に関するファイルをホストからDocker内にコピー
COPY package.json yarn.lock tsconfig.json ./
# yarn install する
RUN yarn
# yarn install 後、全ファイルをコピーすることで、パッケージ関連がコピーされ、キャッシュが効くようになり高速化
COPY . .
CMD [ "yarn", "start" ]
```


```yaml:docker-compose.yaml
    # compose fileのフォーマットバージョン(バージョンによって使える記法が違う)
    version: '3.7'
    services:
        node:
            build:
            # 使用するDockerFileのDirectoryを指定
              context: ../../
              # 使用するDockerFileの名前を指定(Dockerfile.Nodeはdocker-compose.yamlと同じディレクトリにあるが、contextで2階層上を使用すると指定している、だからわざわざdocler/.devcontainer/ という風にしてDockerfile.Nodeを指定)
              dockerfile: docker/.devcontainer/Dockerfile.Node
            volumes:
            # ローカルのディレクトリが接続（マウント）する作業ディレクトリを指定(srcフォルダをusr/app/src にマウントしている)
            - ../../src:/usr/app/src
            # 外部に対して公開するポート番号
            ports:
            - "3000:3000"
            # コンテナを起動させ続けるか管理するフラグ
            tty: true
            # 環境によってはDockerでHotReloadが効かなくなるので環境変数により有効化する
            environment:
              - CHOKIDAR_USEPOLLING=true
```


```json:devcontainer.json
    {
        "name": "Existing Docker Compose (Extend)",
        "dockerComposeFile": [
            "docker-compose.yml"
        ],
        "service": "node",
        "workspaceFolder": "/usr/app/", // VSCodeのTerminalが開くディレクトリを設定
        "settings": {
            "terminal.integrated.shell.linux": null,
            "files.trimTrailingWhitespace": true, // ファイル保存時に行末の空白自動削除
            "editor.formatOnSave": true // ファイル保存時に自動フォーマットが実行される
        },
        // Remote Containers で起動した際にVSCodeの拡張機能をインストール
        "extensions": ["eamodio.gitlens","chakrounanas.turbo-console-log","visualstudioexptteam.vscodeintellicode","esbenp.prettier-vscode","dbaeumer.vscode-eslint","shardulm94.trailing-spaces","msjsdiag.debugger-for-chrome","christian-kohler.path-intellisense","usernamehw.errorlens","gizak.shortcuts","coenraads.bracket-pair-colorizer-2"],
        // Remote Containers で起動した際にgitをインストール
        "postCreateCommand": "apt-get update && apt-get install -y git",
    }
```

## 苦戦した点

1. コンテナ内でホットリロードが効かない
    1. docker-compose内でCHOKIDAR_USEPOLLINGを設定することで解決

2. yarn start が遅い
    1. 一番苦労した点、コンテナ内だと5分かかることもありました。(ローカルだと10秒で終わる)
    2. 原因はyarn がキャッシュされておらず一々node_modulesを作成してたから
       1. 下記の記事の内容で解決しました
          1. [Dockerfile入門する](https://note.com/kawa1228/n/n49b5495f5132)
    3. Docker for Macは遅いらしいのでMacの方は注意が必要らしいです。
       1. [フロントエンドの開発環境に Docker は不要(少なくともMacでは)](https://mizchi.hatenablog.com/entry/2019/04/07/074634)

## 経緯

1. Excelや社内Wikiなどで書かれた環境構築資料の通りにやってもエラーが出て環境構築できない
2. 結果、環境構築だけで時間が消える
3. プロジェクトメンバーが増える度に同じ時間が無駄になる
4. 溜まっていく疲労と虚無感
5. Remote Containersなら秒で終わる！
6. これからはコンテナが入っていれば環境構築が秒で終わる
7. みんな幸せ

## 参考資料

[Reactの開発環境をDockerで整えよう](https://code-ship-blog.wemotion.co.jp/technology/react%E3%81%AE%E9%96%8B%E7%99%BA%E7%92%B0%E5%A2%83%E3%82%92docker%E3%81%A7%E6%95%B4%E3%81%88%E3%82%88%E3%81%86/)

[Docker Composeの仕様について混乱しがちな箇所を整理した](https://qiita.com/hgsgtk/items/0fc14802c3234e95427f#version)

[VSCode Remote ContainersでGitにSSH接続でpushする (Windows)](https://wonwon-eater.com/vscode-remote-containers-git/)

[Dockerfile入門する](https://note.com/kawa1228/n/n49b5495f5132)

[docker-composeでreact環境構築(更新版)](https://qiita.com/kerochelo/items/055781400367ef210266)

[Todo-App-Client](https://github.com/yuuta-wata/Todo-App-Client)

[Dockerizing a React App](https://mherman.org/blog/dockerizing-a-react-app/)