5
Help us understand the problem. What are the problem?

posted at

updated at

Organization

React + Express + Docker の環境構築

Reactで作成した画面からExpressで作成したAPIを呼び、取得したデータを画面表示するところまでを構築していきます。
React/Expressはそれぞれ別のDockerコンテナで動作させます。

ディレクトリ

app/
 ├── docker/
 │   ├── docker-compose.yml
 │   └── Dockerfile
 ├── backend/
 └── frontend/

docker/ の2ファイルはホスト側で作成しますが、その他の backend/frontend/ 内のファイルは全てコンテナ側で作成していきます。

Docker

Dockerfiledocker-compose.yml を作成し、コンテナを起動します。

ファイル作成

React、Express で共通で使う Dockerfile を1つ作成します。

Dockerfile
FROM node:14

今回はひとまずnodeが動けば良いので何も設定していません。

次に docker-compose.yml を作成します。

docker-compose.yml
version: '3'

networks:
  react_express:
    driver: bridge

services:
  frontend:  # React用のコンテナ
    build: .
    container_name: front
    tty: true
    volumes:
      - ../frontend:/frontend
    working_dir: "/frontend"
    ports:
      - 3001:3000
    networks:
      - react_express
  backend:  # Express用のコンテナ
    build: .
    container_name: back
    tty: true
    volumes:
      - ../backend:/backend
    working_dir: "/backend"
    ports:
      - 3002:3000
    networks:
      - react_express
  • network : 2つのコンテナを同じネットワーク内に配置します。
  • volumes : 開発の便宜上、ホストとコンテナでファイル共有しています。
  • ports : frontend、backendの各サーバ用のポート 3000 を、それぞれホストのポート 3001、3002 に転送しています。

コンテナの起動

コンテナを起動します。

$ cd docker/
$ docker-compose up -d
...

$ docker-compose ps
back    docker-entrypoint.sh node   Up      0.0.0.0:3002->3000/tcp,:::3002->3000/tcp
front   docker-entrypoint.sh node   Up      0.0.0.0:3001->3000/tcp,:::3001->3000/tcp

UpとなっていればOKです。

Express (Backend)

プロジェクト作成

docker exec を使って、Express用のコンテナ (back) に入ります。

$ docker exec -u node -it back /bin/bash

package.json を作成します。

$ npm init -y

Expressをインストールします。

$ npm install express

APIの作成

index.js を作成します。

index.js
const express = require('express');
const app = express();

const port = 3000;

app.get('/user', (req, res) => {
  res.json([{
    id: 1,
    name: "Taro"
  }, {
    id: 2,
    name: "Jiro"
  }]);
});

app.listen(port, () => console.log(`Server running on port ${port}`));

/user にリクエストが来たときに、jsonデータを返すようにしています。

Expressサーバの起動

準備ができたので、Expressサーバを起動します。

$ node index.js
Server running on port 3000

React (Frontend)

プロジェクト作成

別のターミナルを立ち上げ、docker exec を使って、React用のコンテナ (front) に入ります。

$ docker exec -u node -it front /bin/bash

create-react-app コマンドを使って、プロジェクトを作成します。
(ドットを付けることで、ディレクトリ直下に作成できます)

$ npx create-react-app .

Proxyの設定

Dockerのネットワーク環境における Front/Backend の各オリジン ( http://xxx:yy )は、

  • Frontend : http://frontend:3000
  • Backend : http://backend:3000

のように異なるため、CORS (Cross-Origin Resource Sharing) の設定をする必要があります。
ここでは、Front側に Proxy を使う方法で回避します。以下2パターンのどちらかを使います。

方法1: package.json に proxy を設定する

package.json に以下を追記します。

pacage.json
  "proxy": "http://backend:3000",

この設定があると、text/html 以外のヘッダのリクエストを proxy のアドレスを origin としてリクエストするようになるため、Same-Origin として認識されます。

方法2: http-proxy-middleware を使う

複数の proxy を設定したい場合にはこちらの方法を使います。

src/setupProxy.js を作成します。

src/setupProxy.js
const proxy = require('http-proxy-middleware')

module.exports = function(app) {
  app.use(proxy('/user', { target: 'http://backend:3000' }))
}

この設定により、Reactアプリに対して /user にリクエストが来たときに http://backend:3000 にリクエストが飛ぶことになり、方法1と同様に Same-Origin として通信できます。
app.use(proxy()) は複数記述できるため、リクエストのパスにより別の proxy に分けて設定することもできます。

ちなみに create-react-app は、npm start の実行時に setupProxy.js を自動で読み込んで処理をするようになっているため、他のファイルにimportをする必要はありません。(ただし、npm run buildでは機能しません。)

画面の作成

src/App.js を以下に編集します。

src/App.js
import { useEffect, useState } from 'react';

const App = () => {
  const [users, setUsers] = useState([]);

  useEffect(() => {
    fetch('/user')
    .then(res => res.json())
    .then(data => {
      setUsers(data);
    }).catch(err => {
      console.log(err)
    });
  }, []);

  return (
    <div>
      {users.map((user, index) =>
        <p key={index}>{ user.name }</p>
      )}
    </div>
  );
}

export default App;

画面読み込み時に fetch('/user') が実行され、Proxyの設定によりExpressサーバ ( http://backend:3000/user ) にリクエストが送られます。
このAPIから取得したデータを users ステートに格納し、画面に表示します。

Reactサーバの起動

Reactサーバを起動します。

$ yarn start

ホスト側のブラウザで http://localhost:3001/ にアクセスすると、
Taro
Jiro
が画面に表示されることが確認できました。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
5
Help us understand the problem. What are the problem?