フロントエンドと API の両方を開発することがたまにあるのですが、悩むのは開発環境をどうするか?です。Ruby on Rails などは、バックエンドとフロントエンドの両方の面倒を見てくれるのですが、巨大すぎてメンテナンスが大変です。
バックエンドは API のみで、View はもはや JSON の提供だけです。フロントエンド開発の比重がかなり高くなりました。ですので、Ruby on Rails のようなバックエンドベースのアプリケーションでは無駄が多く、操作体系もよくないので、身軽なフロントエンド専用のツールで開発したいです。Ruby は遅いので、フロントエンドの開発は Node ベースでやりたいのです…。
そこで今回は、サーバーサイドは Node.js で、フロントエンドは create-react-app で開発するプロジェクトを紹介します。Docker を利用して、両プロジェクトをコマンド一発で起動できるようにします。
React プロジェクトを作る
まずプロジェクトのディレクトリを作ります。
$ mkdir docker-cra && cd docker-cra
フロントエンド用の React プロジェクトを create-react-app で作ります。
$ yarn create react-app frontend
Docker からローカルサーバーを起動するために Host 名を frontend/.env
ファイルに指定します( .env
ファイルは手動で作ります)。
HOST=0.0.0.0
これを指定して yarn start
を実行すると、http://0.0.0.0:3000
でサーバーが起動します。確認したら ctrl + c
でサーバーを落とします。
次に API プロジェクトを作ります。
API プロジェクトを作る
docker-cra のルートに戻り、API 用のディレクトリを作ります。
$ mkdir api && cd api
package.json を作り、yarn install
を実行して必要なモジュールをインストールします。
{
"name": "api",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"dependencies": {
"express": "^4.17.1",
"node-dev": "^4.0.0"
},
"devDependencies": {},
"scripts": {
"start": "node-dev index.js"
}
}
node-dev とは Node.js でファイルを更新した場合に、自動でサーバーを再起動してくれる開発用のアプリケーションです。
fgnass/node-dev: Zero-conf Node.js reloading
Express は Node.js でウェブアプリケーションを作るときによく利用されるミドルウェアです。
api/index.js
に API サーバーの処理を記述します。
const express = require("express")
const app = express()
app.get("/api/users", function (req, res) {
res.json([{
id: 1, name: "maeda"
}, {
id: 2, name: "takada"
}])
})
app.listen(9999)
api ディレクトリで yarn start
を実行すると、http://localhost:9999
でローカルサーバーが起動します。http://localhost:9999/api/users
にアクセスすると以下のような JSON が返ります。
[
{
"id": 1,
"name": "maeda"
},
{
"id": 2,
"name": "takada"
}
]
api サーバーの起動が確認できたので、ctrl + c で落としておきます。
フロントエンドと api サーバーの起動が確認できたので、Docker から両方を同時に起動できるようにします。
Vagrant の設定
Docker for Mac を使うと、webpack の処理が重すぎて開発できないので、Vagrant で Ubuntu を立ち上げ、その中で Docker を起動するようにします。
Vagrant の設定についての詳細はこちらの記事をご確認ください。
Github Actions を利用した WordPress 開発フロー – to-R Media
Docker や webpack の設定を色々調べてはみたのですが、Docker for Mac がやはりネックでどうしても速度を解決することができませんでした。
プロジェクトルートに Vagrantfile を作ります。(./docker-cra/Vagrantfile
)
Vagrant.configure('2') do |config|
config.vm.box = 'ubuntu/xenial64'
config.vm.hostname = 'my-app'
config.vm.network :private_network, ip: '192.168.50.10'
config.vm.provider :virtualbox do |vb|
vb.gui = false
vb.cpus = 4
vb.memory = 4096
vb.customize ['modifyvm', :id, '--natdnsproxy1', 'off']
vb.customize ['modifyvm', :id, '--natdnshostresolver1', 'off']
end
config.disksize.size = '30GB'
config.mutagen.orchestrate = true
config.vm.synced_folder './', '/home/vagrant/app', type: "rsync",
rsync_auto: true,
rsync__exclude: ['.git/', 'node_modules/', 'log/', 'tmp/']
config.vm.provision 'shell', inline: <<-SHELL
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh
rm get-docker.sh
usermod -aG docker vagrant
curl -L "https://github.com/docker/compose/releases/download/1.25.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
SHELL
end
最終的には http://192.168.50.10:3000 で React が、http://192.168.50.10:9999 で API が起動するようになります。
Vagrant プラグインの mutagen の設定ファイルを、プロジェクトルートに配置します。(./docker-cra/mutagen.yml
)
sync:
app:
mode: "two-way-resolved"
alpha: "./"
beta: "my-app:/home/vagrant/app"
ignore:
vcs: true
paths:
- "/node_modules"
- "/log"
- "/tmp"
ここまでのディレクトリ構成は以下のようになります。
.
├── Vagrantfile
├── api
├── frontend
└── mutagen.yml
vagrant up
コマンドで Ubuntu を起動させてみましょう。最初の起動には10分ほどかかります。処理が終了したら、vagrant status
コマンドを実行してみます。以下のように表示されていれば起動が成功しています。
Current machine states:
default running (virtualbox)
The VM is running. To stop this VM, you can run `vagrant halt` to
shut it down forcefully, or you can run `vagrant suspend` to simply
suspend the virtual machine. In either case, to restart it again,
simply run `vagrant up`.
Vagrant の挙動が確認できたので、vagrant halt
コマンドでシャットダウンしておきます。
次に Docker の設定をします。
Docker の設定
フロントエンド用の Dockerfile です。プロジェクトルートに Dockerfile.frontend
というファイル名で保存します。
FROM node:12.10-alpine
WORKDIR /app
RUN apk update \
&& apk --no-cache add git ca-certificates wget
RUN wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub \
&& wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.30-r0/glibc-2.30-r0.apk \
&& apk --no-cache add glibc-2.30-r0.apk
COPY frontend/package.json .
COPY frontend/yarn.lock .
RUN yarn install
COPY ./frontend .
EXPOSE 3000
CMD yarn start
もうひとつ、api 用の Dockerfile を作ります。Dockerfile.api
というファイル名で保存します。
FROM node:12.10-alpine
WORKDIR /app
RUN apk update \
&& apk --no-cache add git ca-certificates wget
RUN wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub \
&& wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.30-r0/glibc-2.30-r0.apk \
&& apk --no-cache add glibc-2.30-r0.apk
COPY api/package.json .
COPY api/yarn.lock .
RUN yarn install
COPY ./api .
EXPOSE 9999
CMD yarn start
2つのサーバーの準備ができたので、両方を起動するための docker-compose.yml
をプロジェクトルートに作ります。
version: "3"
services:
frontend:
build:
context: .
dockerfile: Dockerfile.frontend
command: "yarn start"
ports:
- "3000:3000"
volumes:
- ./frontend:/app
tty: true
api:
build:
context: .
dockerfile: Dockerfile.api
command: "yarn start"
ports:
- "9999:9999"
volumes:
- ./api:/app
create-react-app のコンテナには必ず tty: true
を設定しましょう。これが無いと http://192.168.50.10:3000/
でプレビューすることができません(数時間ハマりました…)。
最終的なプロジェクト構成は以下のようになります。
.
├── Dockerfile.api
├── Dockerfile.frontend
├── Vagrantfile
├── api
├── docker-compose.yml
├── frontend
└── mutagen.yml
開発する
まずは Vagrant を起動します。
$ vagrant up
Vagrant 上に起動した Ubuntu にログインして、アプリケーションディレクトリに移動します。
$ vagrant ssh
$ cd app/
Docker を起動します(初回の起動には5分ほど時間がかかります)。
$ docker-compose up
以下の画面でターミナルが停止していれば起動しています。
Compiled successfully!
frontend_1 |
frontend_1 | You can now view frontend in the browser.
frontend_1 |
frontend_1 | Local: http://localhost:3000
frontend_1 | On Your Network: http://172.22.0.2:3000
frontend_1 |
frontend_1 | Note that the development build is not optimized.
frontend_1 | To create a production build, use yarn build.
frontend_1 |
http://192.168.50.10:3000/
をブラウザで開いてみると、create-react-app の画面が起動しているはずです。
api も起動しているので、http://192.168.50.10:3000/api/users
をブラウザで開くと、以下のような JSON が確認できます。
まとめ
docker-compose up の1コマンドで、フロントエンドと api の開発の両方が同時にできるようになりました。便利。
僕は現在作っているアプリケーションで上記の組み合わせで開発していますが、create-react-app のファイル更新が Mac 上で行うのと遜色のないスピードで実行されるので、快適に開発できています。
Docker for Mac の遅さに苦しんでいる人はぜひ Vagrant を試してみてください。
今回のファイルはこちらにアップしておきました。
【告知】弊社のメンバーが執筆した書籍が発売されました!
弊社のメンバーが執筆した『初心者からちゃんとしたプロになる JavaScript基礎入門』が発売されました! JavaScriptの基礎からVue.jsまでをカバーしており、初学者から基本の復習をしたい方におすすめの1冊です。
フロントエンドエンジニア積極採用中
株式会社トゥーアールでは現在フロントエンドエンジニア積極的に採用中です!
興味がある人は採用ページをチェック!!