真正高效的热更新需确保模块被正确监听、手动接管工具模块更新、顶层模块安全卸载重建。需验证模块是否被直接import、用import.meta.hot.accept处理导出更新、在main.js中卸载重挂应用实例。

Vite 对 JavaScript 项目开箱即用支持热更新(HMR),但“能用”不等于“高效”——真正高效的热更新,关键在于让模块变更后只重载必要部分、不丢状态、不重复执行副作用。下面从三个实际开发中最常卡住的环节讲清楚怎么做。
确保模块被 HMR 正确监听
很多 JS 模块改了没反应,并非 HMR 关闭,而是它根本没“看到”你这个文件。Vite 的 HMR 是模块粒度的,只响应直接 import 的路径;如果某个工具函数只是被 main.js 全局挂载(比如 app.config.globalProperties.$utils = utils),那它就脱离了 HMR 链路。
- 在目标模块顶部加 console.log('hot:', Date.now()),保存后看控制台是否刷新日志——没出现说明该模块未被纳入监听
- 检查它是否只出现在 tree-shaking 外围或仅被间接引用(如通过 window.xxx 或 this.$xxx 访问)
- 确保它被至少一个当前活跃的 HMR 模块(如入口文件或组件)直接 import
普通 JS/TS 工具模块要手动接管更新
导出对象、函数或常量的工具模块(如 src/utils/request.ts)默认不会自动重载。Vite 不会帮你替换旧引用,改完代码后仍指向原始模块实例。
- 在模块末尾添加 import.meta.hot?.accept(() => { /* 重新导出或重置状态 */ })
- 若导出的是可变对象(如 export const store = { count: 0 }),需用 import.meta.hot.dispose() 清理旧引用,或改用 getter 函数导出(export const getStore = () => ({ count: 0 }))
- 避免在模块顶层写副作用逻辑(如初始化定时器、监听事件),应包裹在 if (import.meta.hot) 分支中统一管理
入口或应用层要做安全卸载与重建
当修改了 App.vue 或 main.js 这类顶层模块时,HMR 默认不会自动重挂载整个应用。必须显式卸载旧实例、创建新实例,否则可能残留 DOM 或事件监听器。
立即学习“Java免费学习笔记(深入)”;
- 在 main.js 中加入 import.meta.hot?.accept(() => { app.unmount(); createApp(App).mount('#app') })
- 若使用全局状态或插件,确保它们支持多次注册(如 Pinia 实例需 new createPinia(),而非复用旧实例)
- 注意:不要在 onMounted 或模块顶层反复执行初始化,应把一次性逻辑移到 import.meta.hot.accept 的回调里


















