Webpack HMR浏览器未输出当前构建的hot-update.json问题求助
我之前也碰到过一模一样的问题——HMR的更新文件总是慢一拍,第一次构建找不到,更新后生成的还是旧的。结合你的配置来看,主要是这几个地方需要调整:
1. 替换Output中的[hash]为[chunkhash](或开发环境直接简化命名)
你当前的output.filename和chunkFilename用了[hash],这是整个构建的全局哈希,每次任何文件变化都会导致所有输出文件的哈希改变。而HMR的hot-update.json是基于单个chunk的变化生成的,全局哈希会干扰HMR的文件映射逻辑,导致更新文件和当前构建不匹配。
修改成这样:
output: { chunkFilename: '[name].[chunkhash].js', // 用chunkhash代替全局hash,基于单个chunk内容生成 filename: '[name].[chunkhash].js', path: __dirname + '/dist/browser', publicPath: `/`, },
如果是纯开发环境,甚至可以直接去掉哈希,简化配置:
output: { chunkFilename: '[name].js', filename: '[name].js', path: __dirname + '/dist/browser', publicPath: `/`, },
2. 完善HMR的Entry配置
你的entry里只加了webpack-hot-middleware/client,但缺少了HMR的核心热加载入口。需要加上webpack/hot/only-dev-server(只热更新,不自动刷新页面)或者webpack/hot/dev-server(热更新失败时自动刷新):
entry: { app: [ 'webpack-hot-middleware/client?path=/__webpack_hmr&timeout=20000&reload=true', // 把HTML转义符&换成&,加上reload=true作为兜底 'webpack/hot/only-dev-server', // 新增这一行,启用HMR核心逻辑 './src/browser/app.tsx', ], },
3. 开发环境替换MiniCssExtractPlugin为style-loader
MiniCssExtractPlugin的HMR支持虽然已经实现,但在开发环境下不如style-loader稳定,还会额外增加构建复杂度。建议开发环境用style-loader,生产环境再切换回MiniCssExtractPlugin:
首先修改module.rules里的css规则:
{ test: /\.(sa|sc|c)ss$/, use: process.env.NODE_ENV === 'development' ? ['style-loader', 'css-loader', { loader: 'postcss-loader', options: { config: { ctx: { minify: false } } } }] // 开发环境用style-loader,关闭压缩 : [ { loader: MiniCssExtractPlugin.loader }, 'css-loader', { loader: 'postcss-loader', options: { config: { ctx: { minify: true } } } }, ] },
然后在plugins里根据环境条件加载MiniCssExtractPlugin:
plugins: [ ...(process.env.NODE_ENV === 'production' ? [new MiniCssExtractPlugin()] : []), // 只在生产环境启用该插件 new HtmlWebpackPlugin({ chunks: ['app'], filename: 'index.html', template: 'src/browser/app.html', title: 'scaffold-typescript-website--express-react', }), new webpack.HotModuleReplacementPlugin({}), ],
4. 确保Webpack Hot Middleware的服务器配置正确
如果你用Express配合webpack-hot-middleware,要确保compiler正确传递给hotMiddleware,并且devMiddleware的writeToDisk选项开启(因为你用的是webpack --watch,需要把文件写入磁盘,而不是只存在内存):
const webpack = require('webpack'); const webpackDevMiddleware = require('webpack-dev-middleware'); const webpackHotMiddleware = require('webpack-hot-middleware'); const { clientConfig } = require('./webpack.config'); const compiler = webpack(clientConfig); // 挂载dev middleware,开启writeToDisk app.use(webpackDevMiddleware(compiler, { publicPath: clientConfig.output.publicPath, writeToDisk: true, // 关键:让webpack把构建文件写入磁盘,而不是只存在内存 })); // 挂载hot middleware app.use(webpackHotMiddleware(compiler, { path: '/__webpack_hmr', }));
之前第一次构建没有生成hot-update.json,很可能是因为devMiddleware默认把文件存在内存里,浏览器请求时找不到,而第二次构建才写入磁盘。
最后验证步骤
- 删掉dist目录,重新执行
webpack --watch - 启动服务器,打开浏览器,此时应该能正常加载页面,且
hot-update.json会在第一次构建后生成 - 修改代码,观察控制台的HMR日志,此时生成的
hot-update.json应该和当前构建的哈希匹配
内容的提问来源于stack exchange,提问作者k2snowman69

