跳到主要内容

hot

2023年05月27日
柏拉文
越努力,越幸运

一、认识


Vite 通过特殊的 import.meta.hot 对象暴露手动 HMR API

interface ImportMeta {
readonly hot?: ViteHotContext
}

type ModuleNamespace = Record<string, any> & {
[Symbol.toStringTag]: 'Module'
}

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

// `InferCustomEventPayload` provides types for built-in Vite events
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
}

1.1 条件守卫

首先,请确保用一个条件语句守护所有 HMR API 的使用,这样代码就可以在生产环境中被 tree-shaking 优化:

if (import.meta.hot) {
// HMR 代码
}

二、hot.accept(cb)


hot.accept 用来接受模块更新, 一旦 Vite 接受了这个更新,当前模块就会被认为是 HMR 的边界。那么,Vite 接受谁的更新呢?这里会有三种情况:

  • 接受自身模块的更新

    if (import.meta.hot) {
    import.meta.hot.accept((mod) => mod.render())
    }
  • 接受某个子模块的更新

    if (import.meta.hot) {
    import.meta.hot.accept('./render.ts', (newModule) => {
    newModule.render();
    })
    }
  • 接受多个子模块的更新

    if (import.meta.hot) {
    import.meta.hot.accept(['./render.ts', './state.ts'], (modules) => {
    console.log(modules);
    })
    }

二、 hot.dispose(cb)


hot.dispose(cb) 来清除任何由其更新副本产生的持久副作用

if (import.meta.hot) {
import.meta.hot.dispose((data) => {
// 清理副作用
})
}

三、hot.prune(cb)


hot.prune(cb) 注册一个回调,当模块在页面上不再被导入时调用。与 hot.dispose 相比,如果源代码更新时自行清理了副作用,你只需要在模块从页面上被删除时,使用此方法进行清理。Vite 目前在 .css 导入上使用此方法。

if (import.meta.hot) {
import.meta.hot.prune((data) => {
// 清理副作用
})
}

四、hot.data


hot.data 在同一个更新模块的不同实例之间持久化。它可以用于将信息从模块的前一个版本传递到下一个版本。注意,不支持对 data 本身的重新赋值。相反,你应该对 data 对象的属性进行突变,以便保留从其他处理程序添加的信息。

import.meta.hot.data.someValue = 'hello'