expressの中でwebpack-dev-serverをミドルウェアとして使う。
概要
webpack-dev-server を express のミドルウェアとして使えるようにします。
環境
- node.js 17.4.0
モジュール
- express 4.17.2
- webpack-dev-middleware 5.3.0
- webpack-hot-middleware 2.25.1
devServer を立ち上げるフロントエンドは完全に別のプロジェクトです。
ディレクトリ構造はこんな感じ
rootDir
│ package.json
│ tsconfig.json
│ webpack.config.ts
│
└─src
│ index.html
│ index.tsx
│
└─pages
_App.tsx
ここにあるwebpack.config.ts
の内容で devServer を立ち上げます。
import webpack from 'webpack'
import HtmlWebpackPlugin from 'html-webpack-plugin'
import path from 'path'
const config: webpack.Configuration = {
name: 'renderer',
target: 'web',
context: path.resolve(__dirname),
entry: ['./src'],
output: {
path: path.resolve(__dirname, 'dist'),
publicPath: '/',
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx'],
},
module: {
rules: [
{
test: /\.tsx$|\.ts$/,
exclude: /node_modules/,
loader: 'ts-loader',
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
scriptLoading: 'blocking',
inject: 'body',
minify: false,
}),
],
devtool: 'source-map',
}
export default config
方法
まずは必要なモジュールをインストールします。
yarn add -D webpack webpack-dev-middleware webpack-hot-middleware
または
npm i -D webpack webpack-dev-middleware webpack-hot-middleware
とりあえずコード全体
import express from 'express'
import path from 'path'
import webpack from 'webpack'
import webpackDevMiddleware from 'webpack-dev-middleware'
import webpackHotMiddleware from 'webpack-hot-middleware'
const useDevServer = async (app: express.Express, cwd: string) => {
const config = (await import(path.resolve(cwd, 'webpack.config.ts'))).default as webpack.Configuration
config.entry = ['webpack-hot-middleware/client?reload=true', './src']
config.plugins?.push(new webpack.HotModuleReplacementPlugin())
const compiler = webpack(config)
app.use(
webpackDevMiddleware(compiler, {
publicPath: config.output?.publicPath,
}),
)
app.use(
webpackHotMiddleware(compiler, {
log: false,
path: '/__webpack_hmr',
heartbeat: 10 * 1000,
}),
)
}
const app = express()
if(process.env.NODE_ENV === 'development') useDevServer(app, process.argv[2] || '.')
app.listen(3030)
順番に見ていきます。
import express from 'express'
import path from 'path'
import webpack from 'webpack'
import webpackDevMiddleware from 'webpack-dev-middleware'
import webpackHotMiddleware from 'webpack-hot-middleware'
const app = express()
//省略
app.listen(3030)
ここでは、モジュールをインポートして express サーバーを立ち上げています。
const useDevServer = async (app: express.Express, cwd: string) => {
const config = (await import(path.resolve(cwd, 'webpack.config.ts'))).default as webpack.Configuration
config.entry = ['webpack-hot-middleware/client?reload=true', './src']
config.plugins?.push(new webpack.HotModuleReplacementPlugin())
const compiler = webpack(config)
app.use(
webpackDevMiddleware(compiler, {
publicPath: config.output?.publicPath,
})
)
app.use(
webpackHotMiddleware(compiler)
)
}
ここで webpack-dev-server を立ち上げています。
今回は一つの関数としてまとめました。引数に express のインスタンスとプロジェクトのルートディレクトリを渡しています。
詳しく見ていきます。
const config = (await import(path.resolve(cwd, 'webpack.config.ts'))).default as webpack.Configuration
config.entry = ['webpack-hot-middleware/client?reload=true', './src']
config.plugins?.push(new webpack.HotModuleReplacementPlugin())
const compiler = webpack(config)
まずimport
を使ってwebpack.config.ts
をインポートしています。
typescript ですが、何もしないでインポートできます。
そして config を少しいじります。
entry にwebpack-hot-middleware/client?reload=true
を、plugins にwebpack.HotModuleReplacementPlugin()
を追加します。
これをしないとリロードがうまく動きません。
最後にwebpack(config)
で compiler を作ります。
app.use(
webpackDevMiddleware(compiler, {
publicPath: config.output?.publicPath,
})
)
app.use(
webpackHotMiddleware(compiler)
)
次にミドルウェアを追加します。
webpackDevMiddlewareにはコンパイラとpublicPath
にconfigで指定したpublicPath
を渡します。
webpackHotMiddlewareにはコンパイラのみを渡します。
これで一度実行してみます。
yarn cross-env NODE_ENV=development ts-node src/app.ts /path/to/project
すると見慣れたwebpack-dev-serverのログが表示されます。
webpack built renderer c4a2c952cc178e81b877 in 8129ms
assets by path render/*.ts 66 bytes
asset render/_App.d.ts 66 bytes [emitted]
assets by path *.ts 12 bytes
asset index.d.ts 12 bytes [emitted]
.....省略
この状態で指定したポートにアクセスすると...
ページが表示されました!!
コンソールにも[HMR] connected
と表示されているので成功ですね。
webpack5でリロードが効かない問題
2022/01/20現在webpack-hot-middlewareはwebpack5においてリロードが効かない問題を抱えています。
このようにIgnored an update to unaccepted module ****
と表示され、更新が無視されてしまいます。
これの対処法としてwebpack.config.ts
でentryに指定したファイルに以下の行を追加します。
//@ts-ignore
if (module.hot) module.hot.accept()
Discussion