🐳

DockerとVS Code Remote Containersを用いたフロントエンド開発環境構築

2021/12/29に公開
2

背景

プロジェクトの新規立ち上げや、新しくプロジェクトに新規メンバーが入った場合に環境構築に手間取ることが多いため、Docker+VS Code Remote Containersのフロントエンドアプリケーション開発環境構築ができるリポジトリを作成しました。

本記事では上記リポジトリを用いた環境構築手順とCreate React Appによる簡単なアプリ開発例を説明します。
また、上記リポジトリをgit cloneしなくても一から同じ環境を構築できるように、リポジトリに含まれるファイル群についてもそれぞれ説明します。

本記事の対象はフロントエンドですが、バックエンドのプロジェクト構築も基本的には同じ知識で構築できるはずです。

前提条件

本記事では以下を前提条件とします。ただし、WindowsやLinuxでも基本的には問題ないはずです。

  • macOS Monterey
  • Visual Studio Code
  • VS Code拡張機能 Remote - Containers
  • Docker Desktop

環境構築手順

環境構築手順を説明します。

はじめに、リポジトリをクローンします。
(用意するファイルは大してないので、手動でファイル群を作成しても良いですが、説明を簡単にするためここでは私の作成したリポジトリを使用します)

git clone https://github.com/LeftLetter/vscode-compose-template.git

uiディレクトリをVS Codeで開き(注:プロジェクトルートを開くわけではない)、左下の緑色のアイコンをクリックします。

Repoen in Containerを選択します。

コンテナのビルドが走るのでしばし待ちます。
画面右下にポップアップが表示され、「show log」をクリックするとログが表示されます。

ビルドが正常に完了した場合、VS Codeの左下にコンテナ名が表示されているはずです。

これでVS Codeからコンテナの中身を直接触ることができるようになります。全てはコンテナ内で完結するので、リンターやフォーマッタをローカルにインストールする必要はありません。

また、カレントディレクトリはバインドマウントされるため、万が一コンテナが消えてしまってもホスト側にファイルは残ります。

次章では構築したコンテナ環境にCreate React Appでフロントエンドアプリケーションを作成し、デバッグする方法を説明します。

Create React Appでアプリを作成し、デバッグしてみる

VS Code内のターミナルで、以下のコマンドを実行し、Reactアプリのテンプレートを作成します。

$ create-react-app test_project
$ shopt -s dotglob
$ mv test_project/node_modules/* node_modules
$ mv test_project/* .
$ rm -rf test_project/

既にChromeが起動している場合、終了します。その後、以下のコマンドでChromeをデバッグモードで起動します。

/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222 --no-first-run --no-default-browser-check

以下のコマンドでdevサーバを起動します。

$ yarn start

Chromeでlocalhost:3000にアクセスし、Create React Appのサンプルページが開くことを確認します。

F5キーを押下し、VS Codeのデバッガを起動します。
適当な箇所でブレークポイントを設定した後、Chromeをリフレッシュし、ブレークポイントでプログラムが停止すればOKです。

設定ファイルの説明

設定ファイル群についてそれぞれ詳細を説明します。

ディレクトリ構成

ディレクトリ構成は以下の通りです。serverディレクトリにはフロントエンドアプリケーション開発のためのモックサーバを、uiディレクトリには開発対象のフロントエンドアプリケーションを配置する想定です。

/
├server/
│ ├.devcontainer/
│ │ ├swagger.yml
│ │ ├Dockerfile
│ │ └devcontainer.json
├ui/
│ ├.devcontainer/
│ │ ├Dockerfile
│ │ └devcontainer.json
│ └.vscode/
│   └launch.json
├.gitignore
├README.md
└docker-compose.yml

ファイルの個別説明

docker-compose.yml

コンテナ起動のエントリーポイントとなります。
https://github.com/LeftLetter/vscode-compose-template/blob/cd880efcc5581b25cb498d48e592967d0ea191bc/docker-compose.yml#L1-L22

ボリューム

https://github.com/LeftLetter/vscode-compose-template/blob/cd880efcc5581b25cb498d48e592967d0ea191bc/docker-compose.yml#L20-L22

ui-node-modules:node-modulesのボリュームマウントです。これによりyarn addなどのコマンドの高速化が可能です。こちらは公式ドキュメントに書かれているテクニックです。必要に応じて、buildやdistなどのディレクトリもボリュームマウントすることでビルドの高速化が見込まれます。

参考:Use a targeted named volume
https://code.visualstudio.com/remote/advancedcontainers/improve-performance#_use-a-targeted-named-volume

ui-extensions:はVS Codeの拡張機能のボリュームマウントです。再ビルドのたびに拡張機能のインストールを行うのを防ぎますが、devcontainers.jsonに新たにインストールしたい拡張機能を追加しても反映されないため、その際はボリュームを削除する必要があります。こちらも同様に、公式ドキュメントに書かれているテクニックです。

参考:Avoiding VS Code extension reinstalls
https://code.visualstudio.com/remote/advancedcontainers/avoid-extension-reinstalls

コマンド

https://github.com/LeftLetter/vscode-compose-template/blob/cd880efcc5581b25cb498d48e592967d0ea191bc/docker-compose.yml#L16

通常、コンテナはエントリーポイントが終了するとシャットダウンされてしまいます。そのため、上記コマンドを設定することでコンテナを永続起動させます。

参考:Use Docker Compose
https://code.visualstudio.com/docs/remote/create-dev-container#_use-docker-compose

Dockerfile

コンテナで実行するコマンドなどを定義します。
フロント側はcreate-react-appでプロジェクトを作成することを想定しています。必要に応じてcreate-vue-appなどをインストールするように変更すれば良いと思います。
https://github.com/LeftLetter/vscode-compose-template/blob/cd880efcc5581b25cb498d48e592967d0ea191bc/ui/.devcontainer/Dockerfile#L1-L3

モックサーバ側はswagger.ymlを配置してSwaggerサーバを起動する想定になっています。必要に応じてJSON Serverのイメージに変更するなど、開発環境に応じて変更すれば良いと思います。

https://github.com/LeftLetter/vscode-compose-template/blob/cd880efcc5581b25cb498d48e592967d0ea191bc/server/.devcontainer/Dockerfile#L1-L11

なお、mswを使用するプロジェクトなど、モックサーバを使用しない場合は、以下のようにdocker-composeを使用しない構成も可能です。
https://github.com/LeftLetter/vscode-react-template

devcontainer.json

主にVS CodeやRemote - Containersの設定を定義します。
https://github.com/LeftLetter/vscode-compose-template/blob/cd880efcc5581b25cb498d48e592967d0ea191bc/ui/.devcontainer/devcontainer.json#L1-L33
※server側は省略

コンテナ設定関連

Remote - Containersの設定はここに定義します。基本的にname以外は変更しなくても問題ないと思います。
https://github.com/LeftLetter/vscode-compose-template/blob/cd880efcc5581b25cb498d48e592967d0ea191bc/ui/.devcontainer/devcontainer.json#L2-L6

VS Codeの拡張機能

コンテナ内にインストールしたい拡張機能はここに定義します。必要に応じて変更してください。
https://github.com/LeftLetter/vscode-compose-template/blob/cd880efcc5581b25cb498d48e592967d0ea191bc/ui/.devcontainer/devcontainer.json#L7-L13

VS Codeの設定

VS Codeの設定はここで定義します。ファイル保存時にESLintとPrettierを実行する設定などを書いています。必要に応じて変更してください。

ここでは、以下の設定をしています。

  • ファイル保存時にESLint+Prettierを実行
  • ファイル保存時にimportを整理
  • VS Codeの設定ファイル(jsonc)に対しても保存時にフォーマット
  • .mdファイルに対してはフォーマットしない(Prettierのフォーマットが日本語を含むマークダウンに対して微妙なため)

https://github.com/LeftLetter/vscode-compose-template/blob/cd880efcc5581b25cb498d48e592967d0ea191bc/ui/.devcontainer/devcontainer.json#L14-L32

launch.json

VS Codeでデバッグするための設定はここで定義します。
フロント側はデバッグモードで起動したChromeにアタッチするようになっています。

"type": "pwa-chrome"としたり、非推奨の拡張機能「Debugger for Chrome」をインストールする記事もありますが、古い設定なので注意してください。"type": "chrome"とすることで、VS Code内蔵のデバッガを使用できます。

https://github.com/LeftLetter/vscode-compose-template/blob/cd880efcc5581b25cb498d48e592967d0ea191bc/ui/.vscode/launch.json#L1-L13

おまけ1:Docker Desktop for Macが遅い問題について

Docker Desktop for Macのコンテナだとビルド等々がローカルより遅いという問題は広く知られています。
遅いのは事実ですが、千差万別のスキルを持ったメンバーが集まった時に、ローカルの環境を汚さないことと環境の共通化ができることのメリットの方が大きいと考えています。

また、まだExperimentalですが、ファイルシステムを変更することで高速化できる可能性があるようです。

参考:Docker for Macの新しいファイルシステムVirtioFSを試してみた
https://zenn.dev/takc923/articles/1eb61e531e3704

参考:Docker Desktop for Macを使ってる人はみんな今すぐvirtiofsを使うんだ! - Sweet Escape
https://www.keisuke69.net/entry/2022/03/25/083002

※ただし、手元のIntel Macではむしろ遅くなりました

おまけ2:Docker Desktop有料化について

あまり試していませんが、Rancher Desktop+Docker CLIで代替できそうです。

参考:Rancher Desktop
https://rancherdesktop.io/

参考:まるでDocker Desktop!!Rancher Desktopの登場です - Qiita
https://qiita.com/moritalous/items/14d4099023981dcf4fd2

GitHubで編集を提案

Discussion

LeftLetterLeftLetter

ありがとうございます。修正しました。
どうやら記事を書いていた時とページ構成が変わっていたようです。