🔥 面试官: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 热更新,是我们平时用得最多、却最容易忽视的机制之一。

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

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

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

相关推荐
程序员爱钓鱼4 分钟前
Go语言泛型-泛型约束与实践
前端·后端·go
前端小巷子6 分钟前
web从输入网址到页面加载完成
前端·面试·浏览器
江城开朗的豌豆6 分钟前
Vue路由动态生成秘籍:让你的链接'活'起来!
前端·javascript·vue.js
晓得迷路了7 分钟前
栗子前端技术周刊第 88 期 - Apache ECharts 6.0 beta、Deno 2.4、Astro 5.11...
前端·javascript·echarts
江城开朗的豌豆12 分钟前
在写vue公用组件的时候,怎么提高可配置性
前端·javascript·vue.js
江城开朗的豌豆13 分钟前
Vue路由跳转的N种姿势,总有一种适合你!
前端·javascript·vue.js
江城开朗的豌豆13 分钟前
Vue路由玩法大揭秘:三种路由模式你Pick谁?
前端·javascript·vue.js
江城开朗的豌豆14 分钟前
Vue路由守卫全攻略:给页面访问装上'安检门'
前端·javascript·vue.js
小磊哥er21 分钟前
【前端工程化】前端组件模版构建那些事
前端
前端 贾公子22 分钟前
monorepo + Turborepo --- 开发应用程序
java·前端·javascript