2、说说webpack的热更新是如何做到的?原理是什么?

张开发
2026/4/11 10:08:15 15 分钟阅读

分享文章

2、说说webpack的热更新是如何做到的?原理是什么?
目录 什么是 HMR 核心原理整体架构关键步骤拆解1️⃣ 建立 WebSocket 连接2️⃣ 文件变化触发重新编译3️⃣ 服务端推送消息4️⃣ 客户端拉取更新5️⃣ HMR Runtime 替换模块6️⃣ 冒泡机制 完整流程图 面试如何回答得出彩 黄金回答框架3层递进⚡ 可以追加的亮点 什么是 HMRHMRHot Module Replacement热模块替换是 Webpack 的核心功能之一允许在不刷新整个页面的情况下将修改的模块替换掉同时保留应用状态。 核心原理整体架构文件系统变化 ↓ Webpack 重新编译只编译变化的模块 ↓ 通过 WebSocket 通知浏览器 ↓ 浏览器拉取新模块chunk ↓ HMR Runtime 替换旧模块 ↓ 页面局部更新不刷新关键步骤拆解1️⃣ 建立 WebSocket 连接webpack-dev-server 启动时会在客户端注入一段HMR Runtime代码同时与服务端建立WebSocket长连接。// webpack-dev-server 在客户端注入类似这样的代码 const socket new WebSocket(ws://localhost:8080); socket.onmessage (event) { const message JSON.parse(event.data); if (message.type hash) { // 记录最新的 compilation hash currentHash message.data; } if (message.type ok) { // 触发检查更新 hotCheck(); } };2️⃣ 文件变化触发重新编译Webpack 通过文件监听watch mode检测文件变化只重新编译受影响的模块增量编译编译完成后生成两个关键文件[hash].hot-update.json— 描述哪些模块发生了变化[chunkId].[hash].hot-update.js— 变化模块的新代码3️⃣ 服务端推送消息// WebSocket 推送的消息格式 { type: hash, data: abc123 } // 新的 hash { type: ok } // 编译完成4️⃣ 客户端拉取更新浏览器收到通知后通过AJAX请求hot-update.json获取变化的 chunk 列表再用JSONP方式加载对应的hot-update.js。// 伪代码示意 fetch(/${hash}.hot-update.json) .then(res res.json()) .then(({ c: changedChunks }) { // 动态加载变化的 chunk changedChunks.forEach(chunkId { loadScript(/${chunkId}.${hash}.hot-update.js); }); });5️⃣ HMR Runtime 替换模块新模块代码加载后HMR Runtime 会找到需要替换的模块调用旧模块的dispose回调清理副作用用新模块替换模块缓存module注册表调用新模块的accept回调触发局部更新// 开发者在代码中配置接受更新 if (module.hot) { module.hot.accept(./component, () { // 模块更新后的回调逻辑 const newComponent require(./component).default; reRender(newComponent); }); }6️⃣ 冒泡机制如果某个模块没有配置accept更新请求会向上冒泡到父模块直到找到一个处理者如果一直到入口都没找到则降级为整页刷新。 完整流程图开发者修改代码 │ ▼ Webpack Watch 检测变化 │ ▼ 增量重新编译 → 生成 hot-update.json hot-update.js │ ▼ webpack-dev-server 通过 WebSocket 推送 hash 和 ok 消息 │ ▼ 客户端 HMR Runtime 收到消息 │ ├── AJAX 请求 hot-update.json确认哪些模块变了 │ └── JSONP 加载 hot-update.js新模块代码 │ ▼ 执行 module.hot.accept 回调 │ ▼ 局部更新 UI保留应用状态 ✅ 面试如何回答得出彩 黄金回答框架3层递进第一层说清楚是什么HMR 是 Webpack 提供的热模块替换能力核心价值是在不刷新页面的前提下精准替换发生变化的模块保留应用运行状态极大提升开发效率。第二层讲清楚原理重点实现上分为几个环节WebSocket维持服务端与客户端的实时通信文件变化触发 Webpack 增量编译产出hot-update.json和hot-update.js客户端通过AJAX JSONP拉取更新内容HMR Runtime执行模块替换并触发module.hot.accept回调若模块没有声明接受更新会沿模块树冒泡直到降级整页刷新第三层体现深度加分项值得注意的是HMR 能保留状态是因为替换的是模块级别的代码而不是重新执行整个 JS。React 的react-refresh、Vue 的vue-loader都是在这个机制上封装了组件级别的热替换逻辑让组件状态得以保留。⚡ 可以追加的亮点亮点点说法与 Live Reload 的区别Live Reload 是整页刷新HMR 是模块级精准替换状态不丢失为什么用 JSONP 而不是 fetchJSONP 天然支持跨域且可以直接执行 JS利用 Webpack 的模块注册机制hash 的作用每次编译产生唯一 hash用于对比是否有新版本避免缓存问题Vite 的对比Vite 基于原生 ESMHMR 粒度更细、速度更快是下一代方案一句话总结Webpack HMR 本质是WebSocket 通知 增量编译 运行时模块替换三者协同工作的结果精髓在于用模块替换代替页面刷新同时通过accept/disposeAPI 给开发者自定义控制权。

更多文章