ゼロから始めるVSCode × Docker × React × TypeScript開発環境構築

# はじめに
以前バックエンドのDocker開発環境を以下の記事でまとめたため、今回はフロントエンドのDocker環境を構築するための手順をまとめてみようと思いました。

https://qiita.com/kotattsu3/items/476a207992fd575401e3

# プロジェクトの作成
以下の記事を参考にしました。

https://zenn.dev/rihito/articles/96dfad8d4990f9

今回は超シンプルなものを作っていきます。
適当なプロジェクト名のフォルダ(今回はtest-app)を作成してその中にDockerfileとdocker-compose.ymlファイルを作成してください。
### Dockerfile
自分は大体安定版Versionを使うため、イメージは18-alpineにしています。
プロジェクトフォルダはoptフォルダ下に作ることが多いです。
~~~dockerfile:Dockerfile
FROM node:18-alpine

WORKDIR /opt/react-test-app
~~~
### docker-compose.yml
シンプルな構成にしています。
~~~yml:docker-compose.yml
version: '3'

services:
  test-app:
    image: test-app
    container_name: test-app
    build: .
    restart: always
    tty: true
    volumes:
      - ./react-test-app:/opt/react-test-app
~~~

**ポイントはWORKDIRとvolumesはtest-appではなく更にその下に作成予定のreact-test-appにしているところです。
プロジェクトディレクトリ直下ではなく更にその下のディレクトリにReactのプロジェクトを作成します（理由は後述）。**

ttyの設定はデバッグ時のみで運用時はnginxで動かすので必要なくなります。
このあたりの設定はどのコンテナでも必須だと思います。

# Dockerコンテナの作成
Dockerを立ち上げます。
~~~bash
$ sudo service docker start
~~~
コンテナを立ち上げます。
~~~bash
$ docker compose build
$ docker compose up -d
~~~
react-test-appフォルダが作成されると思います。

# Reactプロジェクトを作成
以下のサイトを参考にしています。

https://ja.reactjs.org/docs/create-a-new-react-app.html

VSCodeのリモートエクスプローラーでコンテナが見えるようになっているはずなので立ち上げます。
空のreact-test-appが作業ディレクトリになっているはずです。

ターミナルで以下のコマンドを実行します（TypeScriptで書きたいので--templateで指定しています）。
~~~bash
$ npx create-react-app ./ --template typescript
~~~

Reactプロジェクトのディレクトリ構造を1つ下げた理由は。Dockerfile等別のファイルやフォルダが存在しているとcreate-react-appのコマンドが実行できなくなるからです。

動作テストしてみます。
~~~bash
$ npm start
~~~

親の顔より見た画面が立ち上がります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2497780/28dd61ea-388a-cf59-6d24-ac3fcc5a1bec.png)
ctrl+Cで終了します。

# デバッグ環境設定
このままだとブレークを張ったり変数の中身を見たりできないのでデバッグ環境を整えていきます。
以下のサイトを参考にしました。

https://zenn.dev/rhene/articles/setup-vscode-to-react-debug

### tasks.jsonの作成
上タブから「ターミナル」、「タスクの構成…」、「npm start」の順でクリックしていきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2497780/73be19c5-ba8d-fe27-e31a-6fd0a0cd47f1.png)


作成されたtasks.jsonの中身をすべて消し、以下の内容に書き換えます。
~~~json:tasks.json
{
    "version": "2.0.0",
    "tasks": [
        {
            "type": "npm",
            "script": "start",
            "label": "npm: start",
            "detail": "react-scripts start",
            "group": {
                "kind": "test",
                "isDefault": true
            },
            "isBackground": true,
            "problemMatcher": {
                "owner": "custom",
                "pattern": {
                    "regexp": "ˆ$"
                },
                "background": {
                    "activeOnStart": true,
                    "beginsPattern": "Compiling...",
                    "endsPattern": "Compiled .*"
                }
            }
        }
    ]
}
~~~

### launch.jsonの作成
ブラウザはGoogleChromeとします。
上タブから「実行」、「構成の追加」、「Web App(Chrome)」を選択していきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2497780/d1bdce9a-5df8-6feb-4469-2b00ecaa3e20.png)


またjsonファイルが作成されるので以下の内容に書き換えます。
~~~json:launch.json
{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "pwa-chrome",
            "request": "launch",
            "preLaunchTask": "npm: start",
            "name": "Launch Chrome against localhost",
            "url": "http://localhost:3000",
            "webRoot": "${workspaceFolder}",
            "sourceMaps": true,
            "sourceMapPathOverrides": {
                "webpack:///./*": "${webRoot}/src/*"
            }
        },
    ]
}
~~~

### .envファイルの作成
デバッグに関係のないブラウザを起動しないようにするために.envファイルを作成します。
~~~bash
$ echo BROWSER=none > .env
~~~

最終的なディレクトリ構成はこのようになっていればOKです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2497780/5bb83ec4-fae1-86e4-bb9c-3718776dc75a.png)

### 動作確認
適当にブレークポイントを張ってデバッグ機能が動作するか確認します。
左タブの「実行とデバッグ」を選び、「デバッグの開始」をクリックします（F5キーでもいいです）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2497780/024e7f03-94f0-4ced-3556-c58d7b0efed6.png)

きちんと動作していますね。

# 拡張機能のインストール
開発する上で必要な拡張機能をインストールしていきます。
拡張機能は以下の記事でオススメされているものをインストールすればいいと思います。

https://qiita.com/newt0/items/b7810fb38c339ec5e4a7

# volume trickの設定
node-modulesをホスト側にマウントしないためにvolume trickという中二病的な名前の技を使います。
以下の記事を参考にしています。

https://qiita.com/b-coffin/items/72cea44a390bd1a984b6

一度Dockerコンテナを抜け出し、docker-composeファイルを以下のように書き換えます。
~~~yml:docker-compose.yml
version: '3'

services:
  test-app:
    image: test-app
    container_name: test-app
    build: .
    restart: always
    tty: true
    volumes:
      - ./react-test-app:/opt/react-test-app
      - exception-volumes:/opt/react-test-app/node_modules

volumes:
  exception-volumes:
    name: exception-test-app
~~~

コンテナの再生成を行います。
~~~bash
$ docker compose build
$ docker compose up -d
~~~

これでコンテナ内にnodeモジュールをインストールしてもホスト側に干渉されなくなります。

これで開発環境構築が完了しました。

# 最後に
Pythonと比べるとReactプロジェクトのディレクトリ関係やvolume trickの設定などで工程は増えてしまいますね・・・
自分はPythonと比べてフロントの経験が非常に浅いため、間違えている部分や一般的では部分もあるかもしれません。
より良いものがあればコメント等で教えていただけると幸いです。