HMR API
注意
这是客户端 HMR API。有关在插件中处理 HMR 更新的信息,请参阅 handleHotUpdate。
手动 HMR API 主要面向框架和工具作者。作为最终用户,框架特定入门模板很可能已经为您处理了 HMR。
Vite 通过特殊的 import.meta.hot
对象公开其手动 HMR API
interface ImportMeta {
readonly hot?: ViteHotContext
}
interface ViteHotContext {
readonly data: any
accept(): void
accept(cb: (mod: ModuleNamespace | undefined) => void): void
accept(dep: string, cb: (mod: ModuleNamespace | undefined) => void): void
accept(
deps: readonly string[],
cb: (mods: Array<ModuleNamespace | undefined>) => void,
): void
dispose(cb: (data: any) => void): void
prune(cb: (data: any) => void): void
invalidate(message?: string): void
on<T extends string>(
event: T,
cb: (payload: InferCustomEventPayload<T>) => void,
): void
off<T extends string>(
event: T,
cb: (payload: InferCustomEventPayload<T>) => void,
): void
send<T extends string>(event: T, data?: InferCustomEventPayload<T>): void
}
必需的条件保护
首先,请确保使用条件块保护所有 HMR API 使用,以便可以在生产环境中对代码进行 tree-shaking
if (import.meta.hot) {
// HMR code
}
TypeScript 的 IntelliSense
Vite 在 vite/client.d.ts
中提供了 import.meta.hot
的类型定义。您可以在 src
目录中创建一个 env.d.ts
文件,以便 TypeScript 获取类型定义
/// <reference types="vite/client" />
hot.accept(cb)
要使模块能够自我接受更新,请使用 import.meta.hot.accept
并提供一个回调函数,该函数接收更新后的模块。
export const count = 1
if (import.meta.hot) {
import.meta.hot.accept((newModule) => {
if (newModule) {
// newModule is undefined when SyntaxError happened
console.log('updated: count is now ', newModule.count)
}
})
}
“接受”热更新的模块被视为HMR 边界。
Vite 的 HMR 实际上并没有交换最初导入的模块:如果 HMR 边界模块重新导出来自依赖项的导入,则它负责更新这些重新导出(并且这些导出必须使用 let
)。此外,来自边界模块上游的导入者将不会收到更改通知。这种简化的 HMR 实现足以满足大多数开发用例,同时允许我们跳过生成代理模块的昂贵工作。
Vite 要求此函数的调用在源代码中以 import.meta.hot.accept(
(空格敏感)的形式出现,以便模块能够接受更新。这是 Vite 执行静态分析以启用模块的 HMR 支持的必要条件。
hot.accept(deps, cb)
模块还可以接受来自直接依赖项的更新,而无需重新加载自身。
import { foo } from './foo.js'
foo()
if (import.meta.hot) {
import.meta.hot.accept('./foo.js', (newFoo) => {
// the callback receives the updated './foo.js' module
newFoo?.foo()
})
// Can also accept an array of dep modules:
import.meta.hot.accept(
['./foo.js', './bar.js'],
([newFooModule, newBarModule]) => {
// The callback receives an array where only the updated module is
// non null. If the update was not successful (syntax error for ex.),
// the array is empty
},
)
}
hot.dispose(cb)
自我接受的模块或期望被其他模块接受的模块可以使用 hot.dispose
来清理其更新副本创建的任何持久副作用。
function setupSideEffect() {}
setupSideEffect()
if (import.meta.hot) {
import.meta.hot.dispose((data) => {
// cleanup side effect
})
}
hot.prune(cb)
注册一个回调函数,当模块不再在页面上导入时调用。与 hot.dispose
相比,如果源代码在更新时自行清理副作用,并且您只需要在模块从页面中移除时进行清理,则可以使用此回调函数。Vite 目前将其用于 .css
导入。
function setupOrReuseSideEffect() {}
setupOrReuseSideEffect()
if (import.meta.hot) {
import.meta.hot.prune((data) => {
// cleanup side effect
})
}
hot.data
import.meta.hot.data
对象在同一更新模块的不同实例之间保持持久性。它可以用来将信息从模块的先前版本传递到下一个版本。
请注意,不支持重新分配 data
本身。相反,您应该修改 data
对象的属性,以便保留其他处理程序添加的信息。
// ok
import.meta.hot.data.someValue = 'hello'
// not supported
import.meta.hot.data = { someValue: 'hello' }
hot.decline()
这目前是一个空操作,用于向后兼容。如果将来有新的用途,这可能会发生变化。要指示模块不可热更新,请使用 hot.invalidate()
。
hot.invalidate(message?: string)
自我接受的模块可能会在运行时意识到它无法处理 HMR 更新,因此更新需要强制传播到导入者。通过调用 import.meta.hot.invalidate()
,HMR 服务器将使调用者的导入者失效,就像调用者没有自我接受一样。这将在浏览器控制台和终端中记录一条消息。您可以传递一条消息来提供有关失效原因的一些上下文。
请注意,即使您计划立即之后调用 invalidate
,也应始终调用 import.meta.hot.accept
,否则 HMR 客户端将不会侦听对自我接受模块的未来更改。为了清楚地传达您的意图,我们建议像这样在 accept
回调函数中调用 invalidate
import.meta.hot.accept((module) => {
// You may use the new module instance to decide whether to invalidate.
if (cannotHandleUpdate(module)) {
import.meta.hot.invalidate()
}
})
hot.on(event, cb)
侦听 HMR 事件。
以下 HMR 事件由 Vite 自动分派
'vite:beforeUpdate'
当要应用更新时(例如,模块将被替换)'vite:afterUpdate'
当更新刚刚应用时(例如,模块已被替换)'vite:beforeFullReload'
当要发生完全重新加载时'vite:beforePrune'
当不再需要的模块即将被修剪时'vite:invalidate'
当使用import.meta.hot.invalidate()
使模块失效时'vite:error'
当发生错误时(例如,语法错误)'vite:ws:disconnect'
当 WebSocket 连接断开时'vite:ws:connect'
当 WebSocket 连接(重新)建立时
自定义 HMR 事件也可以从插件中发送。有关更多详细信息,请参阅 handleHotUpdate。
hot.off(event, cb)
从事件侦听器中移除回调函数。
hot.send(event, data)
将自定义事件发送回 Vite 的开发服务器。
如果在连接之前调用,则数据将被缓冲并在连接建立后发送。
有关更多详细信息,包括关于 自定义事件类型 的部分,请参阅 客户端-服务器通信。
进一步阅读
如果您想了解更多关于如何使用 HMR API 及其内部工作原理的信息。请查看以下资源