You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 09:07:46