Reactの環境構築(Frontend)
packageのインストール
■ webpack
npm i -D webpack-cli webpack webpack-dev-server html-webpack-plugin
■ babel
# ※変更 プリセットが古くなってたので、新しいプリセットに切り替え
npm uninstall babel-preset-react # 削除用
npm install --save-dev @babel/preset-react @babel/core @babel/preset-env babel-loader
"presets": ["@babel/preset-env", "@babel/preset-react"]
■ loader
🌾 正直よくわかってない。
npm i -D css-loader style-loader
■ React
npm i -S react react-dom
Reactをビルドして画面に表示させてみる
■ ベースとなるHTMLを作成
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>React and Webpack4</title>
</head>
<body>
<section id="index"></section>
</body>
</html>
■ "Hello React!" を描画するシンプルなReactを実装
import React from "react";
import ReactDOM from "react-dom";
const Index = () => {
return <div>Hello React!</div>;
};
ReactDOM.render(<Index />, document.getElementById("index"));
■ webpackの設定ファイルを作成
ここで、html-webpack-pluginの設定をする。
htmlにreactのコードが埋め込まれたものをdestディレクトリ配下に生成するためのやつ。
const HtmlWebPackPlugin = require("html-webpack-plugin");
const path = require('path')
const htmlWebpackPlugin = new HtmlWebPackPlugin({
template: "./src/client/index.html",
filename: "./index.html"
});
module.exports = {
entry: "./src/client/index.js",
output: {
path: path.resolve('dist'),
filename: '[name].js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
}
]
},
plugins: [htmlWebpackPlugin]
};
■ package.jsonにコンパイル用のスクリプトを追記
"scripts": {
"client": "webpack-dev-server --config ./config/webpack.config.js --open --mode development",
"build": "webpack --config ./config/webpack.config.js --mode development"
},
実行してみる。
npm run client

frontの開発サーバーが立ち上がって、Hello React!がブラウザに表示される。
ここでは、webpack-dev-serverを利用して開発用のサーバーを立ち上げている。
npm run build
frontのコードがビルドされて、dist/ 配下にbuildされたコードがdistされる。
expressの環境構築(Backend)
packageのインストール
■ express
npm i -S express
■ babel
npm install --save-dev @babel/preset-env @babel/preset-react @babel/cli @babel/node
本来 ES5 環境であれば server 側にビルドは不要だが、今回は ES6 を利用したいので babel を利用。
# すでに設定ずみのはず
"presets": ["@babel/preset-env", "@babel/preset-react"]
■ その他 実行用
開発時に利用するパッケージたち。
npm i -D nodemon concurrently
# nodemon : 対象のファイルを監視しnodeプロセスを再起動する
# concurrently : 複数のコマンドを並列に実行する
expressサーバーの立ち上げ
clientへのルーティングと、バックエンドAPIを実装。
import express from 'express';
import path from 'path';
const app = express();
// 静的ファイルがリクエストされた場合、dist内からそれを返却する
// ex) http://localhost:3000/index.html, http://localhost:3000/styles.css
app.use(express.static(path.resolve('./', 'dist')));
// /api へのリクエストの場合、JSONレスポンスが返される
app.get('/api', (req, res) => {
res.send({api: 'test'});
})
// 全ての残りのリクエストを index.html にリダイレクト
app.get('*', function (req, res) {
res.sendFile(path.resolve('./', 'dist', 'index.html'))
})
// サーバーの起動
app.listen(3000, ()=> {
console.log('server running');
})
# 追加
"scripts": {
"server": "nodemon src/server/server.js --exec babel-node",
"dev": "concurrently \"npm run client\" \"npm run server\""
※ babel-cli で直接ES6を実行してるので server 側のコードはコンパイルされない。
babel-node is a CLI that works exactly the same as the Node.js CLI, with the added benefit of compiling with Babel presets and plugins before running it.
https://babeljs.io/docs/babel-node
もっと詳しく
babel-node は、babel-cli の一部で、BabelがJavaScriptコードを実行しながらトランスパイルするので、src/server/server.js のコードが事前にトランスパイルされることはなく、そのままES6の形式で保存される。サーバーが実行されるたびに、babel-node がそのコードをリアルタイムでトランスパイルして実行するので、手元に変換後のコードが保存されない。実行してみる。
npm run dev
下記サーバーが並列に立ち上がる。
| サーバー | host | 用途 |
|---|---|---|
| web-dev-server | localhost:8080 | webpack-dev-server |
| express server | localhost:3000 | expressサーバー |
8080, 3000共に ルートにアクセスすると "Hello React!"のページが表示されるはず。
Frontend と Backend の連携
ひとまず、client と server をそれぞれ立ち上げて "Hello React!" のページを表示できるようにはなった。
......が、このままだとフロントからバックエンドのAPIを叩こうとするとポートが違うためCORSで弾かれてしまう。
それを回避するために開発サーバー側にProxyを建てる。
ただ、Proxyは開発時しか必要ないので、dev専用のwebpack.config.jsを用意。
packageのインストール
■ webpack-merge
webpack-mergeは2つのwebpack.configをマージすることができるプラグイン。
これを利用して、開発用の設定のみを切り出す。
npm i -D webpack-merge
const { merge } = require('webpack-merge');
const path = require('path');
const webpackConfig = require('./webpack.config.js');
module.exports = merge(webpackConfig, {
mode: 'development',
devServer: {
historyApiFallback: true,
open: true,
host: 'localhost',
port: 8080,
proxy: [
{
context: ['/api/**'],
target: 'http://localhost:3000',
secure: false,
logLevel: 'debug',
}
],
static: {
directory: path.resolve('./', 'dist')
},
}
})
webpack-dev-serverで/api/ でアクセスした場合のみ、3000に向けてリクエストするProxyが立ち上がる。
この設定をdevの時にのみ読み込むように書き換える。
"scripts": {
"server": "nodemon src/server/server.js --exec babel-node",
"client": "webpack-dev-server --config ./config/webpack.config.dev.js",
"build": "webpack --config ./config/webpack.config.js --mode production",
"dev": "NODE_ENV=development concurrently \"npm run client\" \"npm run server\"",
"start": "NODE_ENV=production npm run build && npm run server"
},
| タスク | 説明 |
|---|---|
| server | expressの立ち上げ |
| client | webpack-dev-serverの立ち上げ |
| build | frontのコードのコンパイル |
| dev | 開発モードで、expressサーバーとwebpack-dev-serverが立ち上がる |
| start | 本番モードで、frontコードをコンパイルし、expressを立ち上げる |
バックエンドAPIを叩くように実装。
import React from "react";
import ReactDOM from "react-dom";
fetch('/api/').then(response => {
console.log(response.json());
})
export const Index = () => {
return <div>Hello React!</div>;
};
ReactDOM.render(<Index />, document.getElementById("index"));
localhost:8080を叩くとバックエンドAPIの結果が返ってくるはず。
その他ツール
ほとんどそのままできたけど、差分だけメモ。
configuration
パッケージインストール時に、js-yamlも必要だった。
npm i config
npm install js-yaml --save
logging
下記のimportが必要だった。
import { logger } from './logger';