跳到内容

HMR API

注意

这是客户端 HMR API。要处理插件中的 HMR 更新,请参阅 handleHotUpdate

手动 HMR API 主要供框架和工具作者使用。作为最终用户,HMR 很可能已经在特定于框架的启动模板中为你处理好了。

Vite 通过特殊的 import.meta.hot 对象公开其手动 HMR API

ts
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
CustomEventName
>(
event
:
T
,
cb
: (
payload
:
InferCustomEventPayload
<
T
>) => void,
): void
off
<
T
extends
CustomEventName
>(
event
:
T
,
cb
: (
payload
:
InferCustomEventPayload
<
T
>) => void,
): void
send
<
T
extends
CustomEventName
>(
event
:
T
,
data
?:
InferCustomEventPayload
<
T
>,
): void }

必需的条件保护

首先,请确保用条件块保护所有 HMR API 的使用,以便代码可以在生产环境中进行 tree-shaking

js
if (import.meta.hot) {
  // HMR code
}

TypeScript 的智能提示

Vite 在 vite/client.d.ts 中为 import.meta.hot 提供了类型定义。你可以在 src 目录中创建一个 vite-env.d.ts,以便 TypeScript 可以获取类型定义

vite-env.d.ts
ts
/// <reference types="vite/client" />

hot.accept(cb)

要使模块自我接受,请使用 import.meta.hot.accept 和一个回调函数,该回调函数接收更新后的模块

js
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)

模块也可以接受来自直接依赖项的更新,而无需重新加载自身

js
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 来清理其更新副本创建的任何持久副作用

js
function 
setupSideEffect
() {}
setupSideEffect
()
if (import.meta.
hot
) {
import.meta.
hot
.
dispose
((
data
) => {
// cleanup side effect }) }

hot.prune(cb)

注册一个回调函数,当模块不再在页面上导入时将调用该回调函数。与 hot.dispose 相比,如果源代码在更新时自行清理副作用,并且你只需要在从页面中删除模块时进行清理,则可以使用此功能。Vite 目前将此功能用于 .css 导入。

js
function 
setupOrReuseSideEffect
() {}
setupOrReuseSideEffect
()
if (import.meta.
hot
) {
import.meta.
hot
.
prune
((
data
) => {
// cleanup side effect }) }

hot.data

import.meta.hot.data 对象在同一更新模块的不同实例之间保持不变。它可用于将来自模块先前版本的信息传递给下一个版本。

请注意,不支持重新分配 data 本身。相反,你应该改变 data 对象的属性,以便保留从其他处理程序添加的信息。

js
// 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

js
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 以及它在底层是如何工作的信息。请查看这些资源

在 MIT 许可证下发布。(083ff36d)