前置き
この「Webpack?Create React App?No、Vite!!」シリーズでは、5回に分けて以下の内容を扱います。
- JSにおける「コンパイル」「バンドル」「ビルド」の理解
- 表題のツールを用いたReact開発環境構築を通じて、1の内容を理解する
- viteの技術的な凄みとその「爆速」ぶりを体感
現状以下のようなタイトルを想定しています。
①コンパイル、バンドル、ビルドを理解しよう
②webpackによるReact開発環境構築[バンドラ/コンパイラ編]←前回
③webpackによるReact開発環境構築[開発サーバー/HMR編]←今回
④Create React AppによるReact開発環境構築
⑤ViteによるReact開発環境構築とその技術的な凄み
ここからの説明は、以下のリポジトリにあるReactを用いたコンポーネント志向の簡単なアプリをベースに進めます。手元に置いていただいて、確認しながら進めていただけるといいと思います。
3.webpackによるReact開発環境構築[開発サーバー/HMR編]
前回までで一通りコンパイルとバンドルに関する設定を終えました。ただ、実際に開発をしていくとなると、このままでは非常に不便なことがあります。それは、コードの更新を確認する際にいちいち既存のコードを手動でビルドし、ブラウザで動作確認/検証をする必要があります。とても面倒です。
そこで開発サーバーの出番です。開発サーバーの役割としては、本番さながらにHTTPリクエストを受け付け、レスポンスを返す簡易サーバーを立てることで、動作確認などといった開発者体験(DX)を高めるということが挙げられます。以下少し詳しく見ていきます。
3.1.開発サーバーで快適な開発環境を準備する
開発用サーバーは、開発者がローカル環境でアプリケーションを実行、テスト、デバッグするために使用されるソフトウェアツールです。開発用サーバーは以下の機能を提供します。
ライブリロード:
ソースコードに変更が加えられたときにブラウザを自動的に更新します。これにより、開発者は変更の結果をすぐに視覚的に確認できます。
ホットモジュールリプレースメント(HMR):
アプリケーションの実行中に特定のモジュール(ソースコードの一部)の変更があればそれを検知し、交換します。この際、ブラウザを完全にリロードすることなく、特定のコードの変更を反映できます。
APIモック:
フロントエンド開発では、サーバーのAPI応答を模倣(モック)することで、バックエンドのサーバーがまだ準備が整っていない場合や、オフラインで作業している場合でも開発を進めることができます。
静的ファイルのサービス:
開発者は開発用サーバーを使用して静的ファイル(HTML、CSS、JavaScriptなど)をブラウザに提供し、それらのファイルがブラウザで正しく動作することを確認できます。
これらの機能を提供することで、開発用サーバーは開発者が効率的に、そして問題を素早く検出して解決できる環境を提供します。ただし、注意点として開発用サーバーはあくまで開発環境で使用されることを想定したものであり、パフォーマンスやセキュリティの観点から本番環境では専用の本番用サーバーが使用されるべきです。
webpackでは、webpack-dev-serverを使います。webpack-dev-serverはwebpackを利用した開発サーバーです。今回は、ファイルの変更を監視してブラウザをリロードするライブリロード機能1とHMRについて理解し、HMRの設定を行なっていきます。セットアップする前にそれぞれの機能がどのような流れで実現されるか理解しましょう。(とりあえず動けばokな人は飛ばしても問題ないです)
3.2. Live Reloading
繰り返しになりますが、ライブリロードは、ソースコードに変更が加えられたときにブラウザを自動的に更新する機能です。一般的には以下のような流れで行われます。
- ファイルシステム1でソースコードが変更されます。
- 開発サーバーがこれを検知し、更新されたソースファイルを読み込みます。
- 開発サーバーは更新されたソースファイルをコンパイルし、バンドルします。
- 開発サーバーはブラウザにリフレッシュの信号を送ります。
- ブラウザは更新されたバンドルをリクエストします。
- 開発サーバーは更新されたバンドルをブラウザに返します。
- ブラウザは更新されたバンドルでページをリロードします。
webpackでを用いて開発サーバーをセットアップする場合、このライブリロードか後述するHMRのどちらか一方を選択して使用することができます。2
3.3.HMR(Hot Module Replacement)
HMRは、特定のモジュール(ソースコードの一部)を交換する機能を提供します。ブラウザを完全にリロードすることなく、特定のコードの変更を反映できます。より詳しい仕組みの説明に関しては以下の記事を参照していただけるといいかなと思います。
注意
一つ目の記事はwebpackのHMRの内部構造理解の参考として載せていますが、執筆年が多少古いので、一部現在のwebpackのバージョンでは不必要な設定が含まれています。(例えばwebpack.HotModuleReplacementPluginは4系以降HMR有効化の場合自動適用されます)
上記記事を踏まえた上で、一般的には以下のフローで機能が実現されています。
- ファイルシステムでソースコードが変更されます。
- ファイルシステムはその変更をWebpackコンパイラに通知します。
- Webpackコンパイラは更新されたモジュールをコンパイルします。
- Webpackコンパイラは更新情報(HMRマニフェスト)をWebpackサーバに通知します。
- WebpackサーバはHMRマニフェストをWebSocket経由でHMRランタイムに送信します。
- HMRランタイムは更新されたモジュールをHTTP経由でリクエストします。
- Webpackサーバは更新されたモジュールをHMRランタイムに返します。
- HMRランタイムは全ページのリロードなしでブラウザに更新を適用します。
3.4.開発サーバーとHMRの設定
事前知識の補強はおしまいにして、セットアップしていきましょう。
まずはインストールをば。
npm i -D webpack-dev-server
configに設定を書きます。
const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
path: path.join(__dirname, "dist", "assets"),
filename: "bundle.js"
},
...
+ devServer: {
+ // 自動でブラウザを開く
+ open: true,
+ //開くポート
+ port: 9000,
+ // HMRの有効化(webpack4系からデフォルトで有効化しているみたいです)
+ hot: true,
+ //配信するコンテンツのルートディレクトリ
+ static: [
+ {
+ directory: path.join(__dirname, "dist"),
+ }
+ ]
+ },
};
次に再ビルドしたものをもとにHTMLを自動生成するプラグインを追加します。
npm i -D html-webpack-plugin
設定も
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
path: path.join(__dirname, "dist", "assets"),
filename: "bundle.js"
},
...
devServer: {
// 自動でブラウザを開く
open: true,
//開くポート
port: 9000,
// HMRの有効化(webpack4系からデフォルトで有効化しているみたいです)
hot: true,
+ plugins: [
+ new HtmlWebpackPlugin({
+ template: 'index.html',
+ filename: 'index.html',
+ hash: true,
+ }),
]
},
};
これだけでいけそうですよね?残念です。上記で基本的なJSファイルのためのセットアップは完了しましたが、Reactのための設定はまた別途必要です。元々はreact-hot-loaderというものが使われてたようですが、現在ではreact側でFast Refleshがネイティブサポートされているようなのでそれを使います。
インストールをば。
npm i react-refresh
また、上記react-refreshとwebpack側との連携をよしなにしてくれるプラグインをインストール
npm i -D @pmmmwh/react-refresh-webpack-plugin
babel-loaderの設定にreact-refresh/babelプラグインを追加
const path = require("path");
+ const ReactRefreshPlugin = require("@pmmmwh/react-refresh-webpack-plugin");
module.exports = {
mode: 'development',
...
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /(node_modules)/,
loader: "babel-loader",
+ options: { plugins: ['react-refresh/babel']},
},
],
plugins: [
new HtmlWebpackPlugin({
template: 'index.html',
filename: 'index.html',
hash: true,
}),
+ new ReactRefreshPlugin()
},
};
ここまでしてようやく
HMRできます。
かなり長かったですね。webpackでも設定をしっかりすればHMRを有効化できることがわかりました。というかそもそもHMRを広く広めたのはwebpackみたいですね。
ここまで2回に分けて、webpackを用いた快適なReact開発環境構築を扱ってきました。本来こんなにたくさんの設定をwebpack側にしてやる必要があるのですね。
さて、次回はCreate React AppというFaceBook社が作った開発ツールを使って、これまでやってきた過程がどのくらい短縮されるのか見ていきます。
次回が気になったり、ためになったと思ってくださった方は、ぜひいいねやストックしてくださると、今後の励みになります。よろしくお願いします。
参考
-
少し話が逸れますが、DockerやVMを用いて開発環境をセットアップしている場合、ローカルファイルのマウントの仕様によってはうまく機能しない場合があります。そのような事象に遭遇した場合、この記事が参考になると思います。 ↩ ↩2
-
https://webpack.js.org/configuration/dev-server/#devserverlivereload ↩