Webpack热重载遇小改动仍触发全量刷新,求排查解决
Webpack热重载触发全量刷新而非局部更新的问题
我的Webpack热重载在代码改动时会触发整个应用全量刷新,而非仅更新改动部分。比如把内联样式从background: "red"改成background: "green",依然会全量刷新,不是热更新。
应用代码
app.tsx
import { createRoot } from 'react-dom/client'; if (module.hot) { module.hot.accept(); } const root = createRoot(document.getElementById('app')); root.render( <div> asdss <input style={{ position: 'fixed', zIndex: 9999, background: 'red', }} /> </div> );
webpack.js
const HtmlWebPackPlugin = require('html-webpack-plugin'); const webpack = require('webpack'); const path = require('path'); const CopyWebpackPlugin = require('copy-webpack-plugin'); require('babel-polyfill'); const plugins = [ new HtmlWebPackPlugin({ template: 'index.html', publicPath: '/', }), new webpack.ProvidePlugin({ process: 'process/browser.js' }), new CopyWebpackPlugin({ patterns: [{ from: 'src/assets/img/favicons', to: 'assets/img' }], }), ]; if (process.env.NODE_ENV === 'development') { plugins.push( new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'), }) ); plugins.push( new webpack.ProvidePlugin({ process: 'process/browser', }) ); } module.exports = { entry: { main: ['babel-polyfill', './src/index.tsx'], }, devtool: 'inline-cheap-source-map', output: { publicPath: '/', filename: '[name].[fullhash].js', path: path.resolve('./dist'), }, module: { rules: [ { test: /\.tsx?$/, exclude: /node_modules/, loader: 'ts-loader', options: { transpileOnly: true, }, }, { test: /\.js$/, exclude: [path.resolve(__dirname, 'node_modules')], use: [{ loader: 'babel-loader' }], }, { test: /\.json$/, use: ['json-loader'], type: 'javascript/auto', }, { test: /\.(png|jpg|gif|svg)$/, use: [ { loader: 'url-loader', options: { limit: 8192, outputPath: 'assets/img/', }, }, ], }, { test: /\.(woff(2)?|ttf|eot|otf)(\?v=\d+\.\d+\.\d+)?$/, use: [ { loader: 'file-loader', options: { name: '[name].[ext]', outputPath: 'assets/fonts/', }, }, ], }, ], }, resolve: { extensions: ['.tsx', '.ts', '.js'], }, plugins, stats: 'none', mode: 'development', devServer: { host: 'localhost', port: 3000, historyApiFallback: true, open: false, hot: true, }, };
解决方案
问题出在当前配置只开启了Webpack基础热重载,但未配合React官方热刷新工具。React 18的createRoot需要依赖react-refresh实现组件级局部更新,仅靠module.hot.accept()无法满足需求。
步骤1:安装依赖
安装热刷新相关核心包:
npm install -D react-refresh @pmmmwh/react-refresh-webpack-plugin react-refresh-typescript
步骤2:修改Webpack配置
1. 添加ReactRefreshWebpackPlugin插件
在开发环境的plugins数组中新增插件:
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin'); // ... 原有代码 if (process.env.NODE_ENV === 'development') { plugins.push( new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'), }) ); plugins.push( new webpack.ProvidePlugin({ process: 'process/browser', }) ); // 添加热刷新插件 plugins.push(new ReactRefreshWebpackPlugin()); }
2. 配置ts-loader的热刷新转换
修改ts-loader的规则,加入自定义转换器:
{ test: /\.tsx?$/, exclude: /node_modules/, loader: 'ts-loader', options: { transpileOnly: true, getCustomTransformers: () => ({ before: [require('react-refresh-typescript')()], }), compilerOptions: { module: 'es2015', }, }, }
3. 优化输出文件名(可选)
开发环境下使用fullhash会导致每次改动生成新文件,影响热更新效率,建议修改为:
output: { publicPath: '/', filename: '[name].js', // 替换原[name].[fullhash].js path: path.resolve('./dist'), },
步骤3:调整app.tsx代码
替换原有热重载逻辑,简化为适配react-refresh的写法:
import { createRoot } from 'react-dom/client'; function App() { return ( <div> asdss <input style={{ position: 'fixed', zIndex: 9999, background: 'red', }} /> </div> ); } const root = createRoot(document.getElementById('app')); root.render(<App />); // 保留基础热重载接受逻辑 if (module.hot) { module.hot.accept(); }
完成以上修改后,重启dev server,修改内联样式时就会触发组件局部热更新,而非全量刷新。
内容的提问来源于stack exchange,提问作者red house 87
相关产品推荐
相关产品推荐

