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 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 移除
if (import.meta.hot) {
// HMR code
}TypeScript 的智慧感知
Vite 在 vite/client.d.ts 中為 import.meta.hot 提供了型別定義。你可以在 tsconfig.json 中新增 "vite/client",這樣 TypeScript 就能識別這些型別定義
{
"compilerOptions": {
"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 邊界 (HMR boundary)。
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 及其底層工作原理的資訊,請檢視以下資源:
