热更新问题

热更新不生效,如何排查?

热更新不生效有很多种可能的原因,在这篇文档中会介绍大部分常见的原因,你可以参照以下内容进行排查。

在开始排查之前,请简单了解一下热更新的原理:

热更新原理
  1. 浏览器和开发服务器建立一个 Web Socket 连接,用于实时通信。
  2. 当开发服务器每次重新编译完成后,会通过 Web Socket 通知浏览器,浏览器向开发服务器发送 hot-update.(js|json) 请求,从而加载编译后的新模块。
  3. 当浏览器收到新的模块后,如果是 React 项目,则会通过 React 官方的 React Refresh 来更新 React 组件,其他框架也是类似。

了解完热更新的原理后,你可以按照以下步骤来进行基本的排查:

1. 检查 Web Socket 连接

打开浏览器的控制台,查看是否有 [HMR] connected. 日志。

  • 如果有,说明 Web Socket 连接正常,请继续检查后续步骤。
  • 如果没有,请打开 Chrome 的 Network 面板,查看 ws://[host]:[port]/rsbuild-hmr 的请求状态,若请求异常,说明热更新失败的原因是 Web Socket 请求没有建立成功。

Web Socket 请求没有建立成功的原因可能有很多种,例如开启了网络代理,导致 Web Socket 请求没有正确发送到开发服务器。你可以检查 Web Socket 请求的地址是否为你的开发服务器地址,如果不是,则可以通过 dev.client 来配置 Web Socket 请求的地址。

2. 检查 hot-update 请求

当你修改一个模块的代码,并触发重新编译后,浏览器会向开发服务器发送若干个 hot-update.jsonhot-update.js 请求,用于获取更新后的代码。

你可以尝试修改一个模块并检查 hot-update.(js|json) 请求的内容,如果请求的内容是最新的代码,说明热更新的请求正常。

如果请求的内容错误,大概率也是由于开启了网络代理,请检查 hot-update.(js|json) 请求的地址是否为你的开发服务器地址,如果不是,则需要调整代理规则,将 hot-update.(js|json) 请求代理到开发服务器地址。

3. 检查其他原因

如果以上两个步骤都没有问题,那么可能是其他原因导致的热更新失败,比如没有符合 React 对热更新的要求,你可以参考下列的问题进行排查。


打包时 external React 后,热更新不生效?

为了保证热更新生效,我们需要使用 React 和 ReactDOM 的开发模式产物。

当你将 React 通过 externals 排除后,通常会通过 CDN 等方式注入 React 的生产模式产物,所以热更新会不生效。

export default {
  output: {
    externals: {
      react: 'React',
      'react-dom': 'ReactDOM',
    },
  },
};

为了解决该问题,你需要引用 React 的开发模式产物,同时安装 React Devtools,安装完成后即可实现热更新。

如果你不确定当前使用的 React 产物类型,可以参考:React 官方文档 - Use the Production Build


开发环境设置文件名的 hash 后,热更新不生效?

通常来说,我们只会在生产模式下设置文件名的 hash 值(即 process.env.NODE_ENV === 'production' 时)。

如果你在开发模式下设置了文件名的 hash,那么可能会导致热更新不生效(尤其是 CSS 文件)。这是因为每次文件内容变化时,都会引起 hash 变化,导致 mini-css-extract-plugin 等工具无法读取到最新的文件内容。

  • 正确用法:
export default {
  output: {
    filename: {
      css:
        process.env.NODE_ENV === 'production'
          ? '[name].[contenthash:8].css'
          : '[name].css',
    },
  },
};
  • 错误用法:
export default {
  output: {
    filename: {
      css: '[name].[contenthash:8].css',
    },
  },
};

开启 https 后,热更新不生效?

当开启 https 时,由于证书的问题,可能会出现 HMR 连接失败的情况,此时打开控制台,会出现 HMR connect failed 的报错。

» WebSocket connection to 'wss://localhost:3000/rsbuild-hmr' failed:
[HMR] disconnected. Attempting to reconnect.

此问题的解决方法为:点击 Chrome 浏览器问题页面的「高级」->「继续前往 some page(不安全)」。

Tips: 当通过 Localhost 访问页面时,「您的连接不是私密连接」字样可能不会出现,可访问 Network 域名进行处理。