HMR API

:::tip 注意 这里是客户端 HMR API。若要在插件中处理 HMR 更新,详见 handleHotUpdate

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

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

  1. interface ImportMeta {
  2. readonly hot?: {
  3. readonly data: any
  4. accept(): void
  5. accept(cb: (mod: any) => void): void
  6. accept(dep: string, cb: (mod: any) => void): void
  7. accept(deps: string[], cb: (mods: any[]) => void): void
  8. dispose(cb: (data: any) => void): void
  9. decline(): void
  10. invalidate(): void
  11. on(event: string, cb: (...args: any[]) => void): void
  12. }
  13. }

必需的条件守卫

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

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

hot.accept(cb)

要接收模块自身,应使用 import.meta.hot.accept,参数为接收已更新模块的回调函数:

  1. export const count = 1
  2. if (import.meta.hot) {
  3. import.meta.hot.accept((newModule) => {
  4. console.log('updated: count is now ', newModule.count)
  5. })
  6. }

“接受” 热更新的模块被认为是 HMR 边界

请注意,Vite 的 HMR 实际上并不替换最初导入的模块:如果 HMR 边界模块从某个依赖重新导出其导入,则它应负责更新这些重新导出的模块(这些导出必须使用 let)。此外,从边界模块向上的导入者将不会收到更新。

这种简化的 HMR 实现对于大多数开发用例来说已经足够了,同时允许我们跳过生成代理模块的昂贵工作。

hot.accept(deps, cb)

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

  1. import { foo } from './foo.js'
  2. foo()
  3. if (import.meta.hot) {
  4. import.meta.hot.accept('./foo.js', (newFoo) => {
  5. // 回调函数接收到更新后的'./foo.js' 模块
  6. newFoo.foo()
  7. })
  8. // 也可以接受一个依赖模块的数组:
  9. import.meta.hot.accept(
  10. ['./foo.js', './bar.js'],
  11. ([newFooModule, newBarModule]) => {
  12. // 回调函数接收一个更新后模块的数组
  13. }
  14. )
  15. }

hot.dispose(cb)

一个接收自身的模块或一个期望被其他模块接收的模块可以使用 hot.dispose 来清除任何由其更新副本产生的持久副作用:

  1. function setupSideEffect() {}
  2. setupSideEffect()
  3. if (import.meta.hot) {
  4. import.meta.hot.dispose((data) => {
  5. // 清理副作用
  6. })
  7. }

hot.data

import.meta.hot.data 对象在同一个更新模块的不同实例之间持久化。它可以用于将信息从模块的前一个版本传递到下一个版本。

hot.decline()

调用 import.meta.hot.decline() 表示此模块不可热更新,如果在传播 HMR 更新时遇到此模块,浏览器应该执行完全重新加载。

hot.invalidate()

现在调用 import.meta.hot.invalidate() 只是重新加载页面。

hot.on(event, cb)

监听自定义 HMR 事件。

以下 HMR 事件由 Vite 自动触发:

  • 'vite:beforeUpdate' 当更新即将被应用时(例如,一个模块将被替换)
  • 'vite:beforeFullReload' 当完整的重载即将发生时
  • 'vite:beforePrune' 当不再需要的模块即将被剔除时
  • 'vite:error' 当发生错误时(例如,语法错误)

自定义 HMR 事件可以由插件发送。更多细节详见 handleHotUpdate