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 の使用を条件付きブロックでガードし、コードがプロダクションでツリーシェイクされるようにしてください。
if (import.meta.hot) {
// HMR code
}TypeScript の IntelliSense
Vite は vite/client.d.ts で import.meta.hot の型定義を提供しています。TypeScript が型定義を認識するように、src ディレクトリに vite-env.d.ts を作成できます。
/// <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()
これは現在 noop であり、下位互換性のために存在します。将来、新しい用途があれば変更される可能性があります。モジュールがホット更新不可能であることを示すには、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 の使用方法とその内部動作についてさらに詳しく知りたい場合は、以下のリソースを確認してください。