本文档介绍了 Vite 的热模块替换 (HMR) 系统,该系统能够在开发过程中实时更新模块,而不会丢失应用程序状态。HMR 系统包含在浏览器中运行的客户端 JavaScript、通过开发服务器进行的服务器端协调以及用于通信的基于 WebSocket 的传输层。
有关更广泛的开发服务器功能的更多信息,请参阅开发服务器。有关扩展 HMR 功能的插件系统的详细信息,请参阅插件系统。
Vite 的 HMR 系统通过客户端-服务器架构运行,其中浏览器与开发服务器保持持久的 WebSocket 连接。当文件发生更改时,服务器会分析依赖项并将定向的更新指令发送给已连接的客户端。
来源:packages/vite/src/client/client.ts1-461 packages/vite/types/hmrPayload.d.ts1-75 packages/vite/types/hot.d.ts1-40
来源:packages/vite/src/client/client.ts171-303 packages/vite/types/hmrPayload.d.ts20-38
HMR 客户端的核心实现围绕着 HMRClient 类和 HMRContext,后者向应用程序代码提供 import.meta.hot API。
| 组件 | 文件位置 | 目的 |
|---|---|---|
HMRClient | packages/vite/src/shared/hmr.ts | 管理更新队列和模块重新加载 |
HMRContext | packages/vite/src/shared/hmr.ts | 实现 import.meta.hot API |
ErrorOverlay | packages/vite/src/client/overlay.ts209-292 | 显示编译错误 |
| WebSocket 传输 | packages/vite/src/client/client.ts41-104 | 处理服务器通信 |
HMR 客户端在应用程序启动时建立连接
客户端在packages/vite/src/client/client.ts13-22 中注入的常量来接收配置。
__HMR_PROTOCOL__、__HMR_HOSTNAME__、__HMR_PORT__ - 连接参数__HMR_TIMEOUT__ - WebSocket 超时配置__HMR_ENABLE_OVERLAY__ - 错误覆盖层设置__WS_TOKEN__ - 认证令牌来源:packages/vite/src/client/client.ts24-104 packages/vite/src/node/plugins/clientInjections.ts17-122
当客户端接收到更新消息时,它会通过结构化的管道进行处理
在packages/vite/src/client/client.ts193-241 中处理 JavaScript 和 CSS 更新的方式不同,以优化用户体验。
来源:packages/vite/src/client/client.ts171-241 packages/vite/types/hmrPayload.d.ts20-38
import.meta.hot API 通过 ViteHotContext 接口实现,为开发者提供了对模块如何响应更新的精细控制。
| 方法 | 签名 | 目的 |
|---|---|---|
accept() | accept(cb?: Function) | 自接受模块更新 |
accept(deps, cb) | accept(deps: string[], cb: Function) | 接受依赖项更新 |
acceptExports() | acceptExports(exports: string[], cb?: Function) | 接受特定导出更新 |
dispose() | dispose(cb: Function) | 更新前清理 |
invalidate() | invalidate(message?: string) | 强制完全重新加载 |
来自playground/hmr/hmr.ts42-83 的自接受模块实现示例
来源:packages/vite/types/hot.d.ts7-39 playground/hmr/hmr.ts42-153 docs/guide/api-hmr.md71-200
HMR 系统使用 WebSocket 连接实现开发服务器和浏览器客户端之间的实时双向通信。
在packages/vite/src/client/client.ts53-94 中的连接逻辑,实现了在主要 WebSocket 端点不可访问的网络配置下的备用机制。
HMR 协议为不同操作定义了特定的负载类型
| Payload Type | 接口 | 目的 |
|---|---|---|
ConnectedPayload | { type: 'connected' } | 确认连接 |
UpdatePayload | { type: 'update', updates: Update[] } | 模块更新 |
FullReloadPayload | { type: 'full-reload', path?: string } | 页面重新加载 |
ErrorPayload | { type: 'error', err: ErrorInfo } | 编译错误 |
CustomPayload | { type: 'custom', event: string, data?: any } | 插件事件 |
来源:packages/vite/src/client/client.ts41-104 packages/vite/types/hmrPayload.d.ts3-74
发生编译错误时,Vite 会显示一个用户友好的错误覆盖层,提供详细的调试信息。
ErrorOverlay 类在 packages/vite/src/client/overlay.ts209-292 创建了一个基于 shadow DOM 的覆盖层,它
错误信息包含结构化数据,以增强调试能力
来源: packages/vite/src/client/overlay.ts209-298 packages/vite/types/hmrPayload.d.ts58-74 packages/vite/src/client/client.ts282-295 docs/guide/api-hmr.md217-229 packages/vite/src/client/client.ts282-295
HMR 系统通过插件 API 为插件提供了扩展和自定义更新行为的钩子。
示例插件实现来自 playground/hmr/vite.config.ts18-40
插件可以建立双向通信通道
来源: playground/hmr/vite.config.ts17-100 playground/hmr/hmr.ts148-152 docs/guide/api-hmr.md217-229 packages/vite/src/client/client.ts282-295
HMR 客户端通过 clientInjectionsPlugin 管理的编译时常量注入来接收配置。
clientInjectionsPlugin 在 packages/vite/src/node/plugins/clientInjections.ts17-117 通过替换占位符常量来注入 HMR 配置
| 占位符 | 运行时值 | 目的 |
|---|---|---|
__HMR_PROTOCOL__ | 'ws' 或 'wss' | WebSocket 协议 |
__HMR_HOSTNAME__ | 服务器主机名 | 连接目标 |
__HMR_PORT__ | HMR 端口号 | WebSocket 端口 |
__HMR_BASE__ | 应用程序基础 URL 路径 | URL 基础路径 |
__HMR_TIMEOUT__ | 超时值 | 连接超时 |
__HMR_ENABLE_OVERLAY__ | 布尔标志 | 错误覆盖层开关 |
HMR 系统通过 packages/vite/types/importMeta.d.ts14-31 与 Vite 的环境变量集成,提供了对以下内容的访问:
import.meta.env.MODE - 当前模式 (development/production)import.meta.env.DEV - 开发标志import.meta.env.BASE_URL - 应用程序基础 URL来源: packages/vite/src/node/plugins/clientInjections.ts68-95 packages/vite/types/importMeta.d.ts23-31