🔥 面试官:Webpack 为什么能热更新?你真讲得清吗?

🔥 面试官:Webpack 为什么能热更新?你真讲得清吗?

面试时,面试官一边翻我的简历,一边抬头问道:

"你写的熟悉 Webpack,对吧?"

"是的,项目构建都是我配的。"

"那我问个简单的:Webpack 热更新是怎么实现的?"

我顿了一下,说:"是 HMR 吧,就是修改代码后自动更新页面,不用刷新。"

面试官眼神一亮:"对,那它怎么知道你改了代码?它更新了哪一块?又是怎么通知浏览器的?"

我脑中开始飞速回忆:dev-server、监听系统、WebSocket、模块缓存、module.hot......

这一问,直接暴露出很多人对 HMR 理解只停留在"能自动刷新页面",但真正面试要讲清楚,需要你能从原理 + 流程 + 代码执行一层层剖析。

🎯 什么是 HMR?

HMR 全称是 Hot Module Replacement,中文叫 热模块替换

当我们修改某个组件的样式或者逻辑时,它会在不刷新整个页面的前提下,只替换那一部分模块代码并重新执行,使得页面状态得以保留。

就比如:

  • 修改组件样式 -> 页面局部更新
  • 修改组件逻辑 -> 组件刷新但状态保留
  • 修改 CSS 文件 -> 样式直接应用,无感刷新

总结就是:HMR 提升了开发效率,优化了前端开发体验。

🧠 热更新发生了什么?

我们从 写代码 -> 到页面刷新 的链路来还原整个过程:

  1. 当我们修改了某个文件,比如 App.vue
  2. Webpack 监听到这个文件发生变化
  3. 重新打包出一个增量模块
  4. 通过 Websocket 通知浏览器有更新
  5. 浏览器接收更新,调用 module.hot.accept 的钩子
  6. 更新被应用到页面,页面局部更新,状态得以保留

其实就是:Webpack HMR 的核心是 "增量构建 + WebSocket 通知 + 模块热替换机制"

下面我们来详细拆解下 Webpack 的具体实现步骤。

⚙️ Webpack 是怎么一步步做的?

我们分成四步拆解:

第一步:监听文件变化(依赖 chokidar)

Webpack 使用 webpack-dev-serverwebpack-dev-middleware 作为中间件启动一个本地开发服务器。

在这个过程中,它会监听项目中所有依赖的模块变化,使用的是 chokidar 等文件系统监听工具。

ts 复制代码
compiler.watch({}, (err, stats) => {
  if (err) console.error(err)
  // 模块发生变化后的处理逻辑
})

一旦监听到某个模块变了,比如我们修改了 App.vue,它会触发重新编译构建。

第二步:只重新编译"变了的部分"

Webpack 不会降整个项目重打包,它会:

  • 比对模块依赖图,分析变化影响了哪些 chunk
  • 使用缓存避免不必要的构建
  • 只输出那些变化的模块和必要的 runtime 更新逻辑

这个过程叫做 增量编译。

打包完之后,Webpack 会给这次构建生成一个 更新的 hash 值 ,比如 c7df1fef63d,用来标识变化内容。

第三步:WebSocket 通知浏览器有模块变了

webpack-dev-server 启动的时候,会建立一个 WebSocket 长连接,客户端和服务端保持实时通信。

当服务端检测到有模块变化时,会通过 WebSocket 发送一条消息:

ts 复制代码
{
  "type": "update",
  "hash": "c7df1fef63d",
  "modules": {
    "./src/App.vue": true
  }
}

浏览器中的 HMR 客户端接收到这个消息后,就会启动热更新流程。

第四步:客户端加载新模块并替换执行

Webpack 会注入一段客户端 HMR runtime(webpack/hot/dev-server.js),它会:

  1. 监听 WebSocket 消息

  2. 当有模块更新时,发送 HTTP 请求获取更新模块

    ts 复制代码
    fetch(`/__webpack_hmr?hash=c7df1fef63d`)
  3. 加载变化的模块内容

  4. 执行 module.hot.accept 钩子

  5. 应用更新,DOM 变化、状态保留

最终实现页面局部更新,不影响数据状态。

一图看懂整个流程机制:

本质上,HMR 是一次模块级别的"热插拔"操作。

🧱 Vue / React 是怎么做热更新的?

Vue3 和 React 里 HMR 是怎么工作的?其实底层还是 Webpack HMR,只是框架包装了一下热替换逻辑。

Vue 的热更新

在 Vue3 项目中:

  • vue-loader 会在组件编译时自动插入 HMR 逻辑
  • Vue 会缓存组件状态并尝试热替换
  • 如果组件逻辑不支持热更新(如组件结构大改),会 fallback 到页面刷新

React 的热更新

React 使用的是 react-refresh,它做了更细粒度的组件替换:

  • 保持组件 state
  • 替换函数组件或 hooks
  • 如果组件树发生破坏,自动恢复

🧪 哪些场景 HMR 会失效?

不是所有改动都能顺利热更新,下面这些情况会 fallback 到刷新页面:

  • 修改 webpack 配置(得重启服务)
  • 修改路由懒加载模块(刷新比较稳妥)
  • 修改模块暴露的接口结构
  • 修改了组件的结构性变动(比如 slot 数量变了)

✍️ 写在最后

Webpack 热更新,是我们平时用得最多、却最容易忽视的机制之一。

如果你也曾像我一样,对热更新原理一知半解,希望这篇文章能帮你真正搞懂每一个关键步骤。

祝你下次面试,不再因为"只会用不会讲"而错失机会!🔥

如果你觉得这篇文章对你有帮助,欢迎点赞 👍、收藏 ⭐、评论 💬 让我知道你在看~ 我会持续更新 前端打怪笔记系列文章 ,👉 记得关注我,不错过每一篇干货更新!❤️

相关推荐
siwangqishiq222 分钟前
Vulkan Tutorial 教程翻译(四) 绘制三角形 2.2 呈现
前端
李三岁_foucsli23 分钟前
js中消息队列和事件循环到底是怎么个事,宏任务和微任务还存在吗?
前端·chrome
尽欢i23 分钟前
HTML5 拖放 API
前端·html
PasserbyX39 分钟前
一句话解释JS链式调用
前端·javascript
1024小神40 分钟前
tauri项目,如何在rust端读取电脑环境变量
前端·javascript
Nano1 小时前
前端适配方案深度解析:从响应式到自适应设计
前端
古夕1 小时前
如何将异步操作封装为Promise
前端·javascript
小小小小宇1 小时前
前端定高和不定高虚拟列表
前端
古夕1 小时前
JS 模块化
前端·javascript
wandongle1 小时前
HTML面试整理
前端·面试·html