express + webpack + BabelでHMRを使いながらIE11対応する
この記事は、「expressとwebpackでHMRする最小構成を試す」の記事にBabelを追加で組み合わせるための記事です。
expressとは?
Node.jsのフレームワークです。今回は、開発環境向けにWEBサーバを簡単に立ち上げるために使用します。
公式サイト
webpackとは?
複数ファイルに分けて管理しているjs(モジュール)を一つのファイルにまとめてくれるツール(モジュールバンドラー)です。
(正確には1つのファイルとは限りませんが、役割に応じてファイルをまとめられます)
別の記事が参考になります。
Babelとは?
ブラウザがまだ対応していない最新のJavaScriptのソースコードを、ブラウザが対応しているソースコードへ変換してくれるツール (トランスパイラ)です。
別の記事が参考になります。
HMR(Hot Module Replacement)とは?
CSS/JSのソースコードを編集した時に、リロード操作(F5を押す等)無しで編集結果がブラウザに反映される仕組みを提供してくれるwebpackの機能です。
別の記事が参考になります。
expressとwebpackとBabelを組み合わせてHMRを使用した開発をする利点
WEBサーバー(express)からwebpackを使用することで、コマンドラインからwebpackを起動させる必要がなくなり、webpackからBabelを使用することでBabelをコマンドラインから起動させる必要が無くなります。
つまり、コンパイル(モジュールをバンドル化し、トランスパイルする)工程が自動化されます。 そして、HMRを使用することでリロードの作業も省くことで開発の高速化が可能になります。
今回は、上記で述べた技術を組み合わせて、IE11対応の開発を行います。
手を動かして、HMRを使いながらIE11対応した開発をする
以下がインストールされていることを前提とします。
- node.js
- npm
以下が手順概要になります。
- npmでプロジェクトを作成する
- express、webpack、Babel等をインストールする
- 必要なファイルを手動で作成する
- コマンドラインでWEBサーバー(express)を立ち上げる
- IE11でアクセスして確認する
- JSファイルを編集し、IE11に反映された結果を確認する
1. npmでプロジェクトを作成する
以下のコマンドを実行します
mkdir express-webpack-babel-hmr-demo
cd express-webpack-babel-hmr-demo
npm init -y
2. express、webpack、Babel等をインストールする
npm install -D webpack webpack-cli webpack-dev-middleware webpack-hot-middleware
npm install -D babel-loader @babel/core @babel/preset-env
npm install --save @babel/polyfill express lodash
3. 必要なファイルを手動で作成する
以下のファイルを手動で作成します。
- ./babel.config.js
- ./index.html
- ./server.js
- ./webpack.config.js
- ./src/index.js
- ./src/foo.js
- ./src/bar.js
以下のようなディレクトリ構造になります。
│ babel.config.js
│ index.html
│ package.json
│ server.js
│ webpack.config.js
│
├─node_modules
│ └─etc...
└─src
bar.js
foo.js
index.js
./package.jsonを以下のように書き換えます。
- - "main": "index.js",
- + "private": true,
- + "dev": "node server",
{ "name": "express-webpack-babel-hmr-demo", "version": "1.0.0", "description": "", "private": true, "scripts": { "dev": "node server", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "MIT", "devDependencies": { "webpack": "^4.29.6", "webpack-cli": "^3.3.0", "webpack-dev-middleware": "^3.6.1", "webpack-hot-middleware": "^2.24.3" }, "dependencies": { "express": "^4.16.4", "lodash": "^4.17.11" } }
./babel.config.jsの内容を次のようにし、babelの動作を設定します。
const presets = [ [ "@babel/env", { targets: { ie: '11' }, useBuiltIns: "usage" } ] ]; module.exports = { presets };
./webpack.config.jsの内容を次のようにし、webpackの動作を設定します。
const webpack = require('webpack'); module.exports = { mode: 'development', entry: ['webpack-hot-middleware/client', './src/index.js'], // 2つのファイルをwebpackの基点とする output: { filename: 'main.js', // 出力されるファイル名 // 出力されるファイルを読み込めるパスを指定する // ファイルはメモリ上に出力され、そのファイルをロードするためのパス // https://webpack.js.org/configuration/output/#outputpublicpath // https://webpack.js.org/guides/public-path/ publicPath: '/example_public_path/' }, module: { rules: [ { test: /\.js$/, // 拡張子が.jsであり exclude: /node_modules/, // ディレクトリがnode_modules以外であれば use: ['babel-loader'] // Babelの対象とする } ] }, plugins: [ new webpack.HotModuleReplacementPlugin(), // HMRを使用するためのプラグイン ] };
./server.js
WEBサーバー(express)の動作を記述します。
const express = require('express'); const webpack = require('webpack'); const webpackDevMiddleware = require('webpack-dev-middleware'); const webpackHotMiddleware = require('webpack-hot-middleware'); const WebpackConfig = require('./webpack.config'); const app = express(); const compiler = webpack(WebpackConfig); // メモリ上にファイルをコンパイルする // ファイルを監視して、変更されていれば再コンパイルする app.use(webpackDevMiddleware(compiler, { publicPath: WebpackConfig.output.publicPath, })); // クライアントに変更を通知する // クライアント側でHMRに対応している箇所はリロードせずに更新される app.use(webpackHotMiddleware(compiler)); // index.htmlを静的に配置しているディレクトリを指定する app.use(express.static(__dirname)); const port = process.env.PORT || 8080; app.listen(port, () => { console.log(`Server listening on http://localhost:${port}, Ctrl+C to stop`); });
./index.html
バンドルファイル(main.js)以外に、ブラウザ(IE11)用のポリフィルを読み込んでいます。
webpackからポリフィルもまとめてバンドルしてみたのですが、現在(2019/03/24)では動作が不安定になるため、CDNを使用しました。
<!doctype html> <html> <head> <title>express + webpack + babelでHMR</title> </head> <body> <script src="https://www.promisejs.org/polyfills/promise-7.0.4.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/event-source-polyfill/0.0.9/eventsource.min.js"></script> <script src="./example_public_path/main.js"></script> </body> </html>
./src/foo.js
export default () => { return 'from foo!'; }
./src/bar.js
export default () => { return 'from bar!'; }
./src/index.js
下部にてHMRを実行するための記述をしています。
ファイルが編集されるとサーバーから変更の通知を受け取り、module.hot.accept()の第1引数で指定したJSが変更されていた場合に第2引数のコールバックが実行されます。
コールバックによってbodyタグを再描画しています。
import _ from 'lodash'; import foo from './foo.js' import bar from './bar.js' const expressAndWebpack = () => { let body = document.querySelector('body'); body.innerHTML = ''; body.innerHTML = _.join(['Hello', 'express', '+', 'webpack', '+' , 'Babel'], ' '); body.innerHTML += `<br>${foo()}`; body.innerHTML += `<br>${bar()}`; return body; } expressAndWebpack(); if (module.hot) { module.hot.accept(['./foo.js', './bar.js'], () => { expressAndWebpack(); }); };
4. コマンドラインでWEBサーバー(express)を立ち上げる
以下のコマンドを実行して、WEBサーバーを立ち上げます。
npm run dev
上記のコマンドは./package.jsonに定義してあり、以下のコマンドと同等です。
node server
5. IE11でアクセスして確認する
以下のURLにアクセスします。
http://localhost:8080/
以下のように表示されていれば、expressとwebpackとBabelの組み合わせは成功です。
Hello express + webpack + Babel + Babel
from foo!
from bar!
6. JSファイルを編集し、IE11に反映された結果を確認する
WEBサーバーを立ち上げたまま、JSファイルを編集します。 以下のJSファイルを編集して保存します。
./src/foo.js
export default () => { return 'from foo!'; } ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ export default () => { return 'FROM FOO!!'; }
表示が以下のように即座に変更されればIE11上でのHMRが成功です。
Hello express + webpack + Babel
from foo!
from bar!
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
Hello express + webpack + Babel
FROM FOO!!
from bar!