vite 热更新(hmr)通过 websocket 协议实现,核心流程是:vite 开发服务器在接收到文件变更通知后,生成包含模块 id 和变更类型的 json 消息,并通过 websocket 推送给浏览器;浏览器端的 vite hmr runtime 收到消息后,调用 import() 动态加载新的模块版本,并执行模块导出的 __vite_hmr_update 函数以更新状态。

服务端如何检测文件变更并发送消息
服务端依赖 fsevents (macOS) 或 chokidar (其他平台) 监听文件系统。当检测到文件变化时,Vite 会计算该文件的模块 ID,构建一个包含 type、updated 或 deleted 信息的对象,并通过已建立的 WebSocket 连接发送给客户端。

const { createServer } = require('vite');
async function start() {
const server = await createServer({
server: {
hmr: true // 默认开启
}
});
await server.listen();
console.log('Vite server started');
}
客户端如何接收消息并更新模块
浏览器端引入 @vite/client,它会自动建立 WebSocket 连接到 /@fs/ 路径下的 HMR 端点。收到消息后,Runtime 会根据模块类型(JS/CSS)采取不同策略。对于 JS 模块,它会尝试重新导入该模块,如果模块导出了 __vite_hmr_update 函数,则调用它传入新模块的依赖列表。
立即学习“Java免费学习笔记(深入)”;

// client-side logic simulation
const ws = new WebSocket('ws://localhost:5173/@vite/client');
ws.onmessage = async (event) => {
const payload = JSON.parse(event.data);
if (payload.type === 'update') {
for (const update of payload.updated) {
await import(update.path + '?t=' + Date.now());
}
}
};
为什么某些组件更新时会重置状态
当 Vite 无法找到模块导出的 __vite_hmr_update 函数,或者变更涉及非 HMR 友好的模块(如入口 HTML 或配置变更)时,Vite 会触发全页刷新(Full Reload)。这是因为 HMR 只能更新可执行的逻辑和数据,无法自动恢复 React/Vue 等框架中未持久化的局部状态(如 useState 或 data),为了避免状态不一致,直接刷新页面是最安全的做法。


















