🔥 面试官:Webpack 为什么能热更新?你真讲得清吗?
面试时,面试官一边翻我的简历,一边抬头问道:
"你写的熟悉 Webpack,对吧?"
"是的,项目构建都是我配的。"
"那我问个简单的:Webpack 热更新是怎么实现的?"
我顿了一下,说:"是 HMR 吧,就是修改代码后自动更新页面,不用刷新。"
面试官眼神一亮:"对,那它怎么知道你改了代码?它更新了哪一块?又是怎么通知浏览器的?"
我脑中开始飞速回忆:dev-server、监听系统、WebSocket、模块缓存、module.hot......
这一问,直接暴露出很多人对 HMR 理解只停留在"能自动刷新页面",但真正面试要讲清楚,需要你能从原理 + 流程 + 代码执行一层层剖析。
🎯 什么是 HMR?
HMR 全称是 Hot Module Replacement,中文叫 热模块替换。
当我们修改某个组件的样式或者逻辑时,它会在不刷新整个页面的前提下,只替换那一部分模块代码并重新执行,使得页面状态得以保留。
就比如:
- 修改组件样式 -> 页面局部更新
- 修改组件逻辑 -> 组件刷新但状态保留
- 修改 CSS 文件 -> 样式直接应用,无感刷新
总结就是:HMR 提升了开发效率,优化了前端开发体验。
🧠 热更新发生了什么?
我们从 写代码 -> 到页面刷新 的链路来还原整个过程:
- 当我们修改了某个文件,比如 App.vue
- Webpack 监听到这个文件发生变化
- 重新打包出一个增量模块
- 通过 Websocket 通知浏览器有更新
- 浏览器接收更新,调用
module.hot.accept
的钩子 - 更新被应用到页面,页面局部更新,状态得以保留
其实就是:Webpack HMR 的核心是 "增量构建 + WebSocket 通知 + 模块热替换机制" 。
下面我们来详细拆解下 Webpack 的具体实现步骤。
⚙️ Webpack 是怎么一步步做的?
我们分成四步拆解:
第一步:监听文件变化(依赖 chokidar)
Webpack 使用 webpack-dev-server
或 webpack-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
),它会:
-
监听 WebSocket 消息
-
当有模块更新时,发送 HTTP 请求获取更新模块
tsfetch(`/__webpack_hmr?hash=c7df1fef63d`)
-
加载变化的模块内容
-
执行
module.hot.accept
钩子 -
应用更新,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 热更新,是我们平时用得最多、却最容易忽视的机制之一。
如果你也曾像我一样,对热更新原理一知半解,希望这篇文章能帮你真正搞懂每一个关键步骤。
祝你下次面试,不再因为"只会用不会讲"而错失机会!🔥
如果你觉得这篇文章对你有帮助,欢迎点赞 👍、收藏 ⭐、评论 💬 让我知道你在看~ 我会持续更新 前端打怪笔记系列文章 ,👉 记得关注我,不错过每一篇干货更新!❤️