Files
gt-agent-company/.agents/skills/vite/references/features-hmr.md
sexygoat 3c62cc1cd1 first
2026-03-31 18:41:52 +08:00

3.2 KiB

name, description
name description
features-hmr Vite's Hot Module Replacement (HMR) client API

HMR API

The HMR API is exposed via import.meta.hot. Primarily for framework and tooling authors.

Conditional Guard

Always guard HMR code for tree-shaking in production:

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

TypeScript Support

Add to tsconfig.json:

{
  "compilerOptions": {
    "types": ["vite/client"]
  }
}

Self-Accepting Module

Module handles its own updates:

export const count = 1

if (import.meta.hot) {
  import.meta.hot.accept((newModule) => {
    if (newModule) {
      console.log('updated: count is now', newModule.count)
    }
  })
}

Accept Dependency Updates

React to changes in dependencies without self-reload:

import { foo } from './foo.js'

foo()

if (import.meta.hot) {
  // Single dependency
  import.meta.hot.accept('./foo.js', (newFoo) => {
    newFoo?.foo()
  })
  
  // Multiple dependencies
  import.meta.hot.accept(
    ['./foo.js', './bar.js'],
    ([newFooModule, newBarModule]) => {
      // Handle updates
    }
  )
}

Cleanup on Update

Clean up side effects before module is replaced:

function setupSideEffect() {
  const interval = setInterval(() => {}, 1000)
  return interval
}

const interval = setupSideEffect()

if (import.meta.hot) {
  import.meta.hot.dispose((data) => {
    clearInterval(interval)
  })
}

Prune Callback

Called when module is no longer imported:

if (import.meta.hot) {
  import.meta.hot.prune((data) => {
    // Cleanup when module is removed from page
  })
}

Persistent Data

Pass data between module instances:

if (import.meta.hot) {
  // Mutate properties, don't reassign data itself
  import.meta.hot.data.count = (import.meta.hot.data.count || 0) + 1
}

Invalidate

Force propagation to importers:

if (import.meta.hot) {
  import.meta.hot.accept((module) => {
    if (cannotHandleUpdate(module)) {
      import.meta.hot.invalidate()  // Propagate to importers
    }
  })
}

HMR Events

Listen to built-in events:

if (import.meta.hot) {
  import.meta.hot.on('vite:beforeUpdate', (payload) => {
    console.log('Update incoming')
  })
  
  import.meta.hot.on('vite:afterUpdate', (payload) => {
    console.log('Update applied')
  })
  
  import.meta.hot.on('vite:beforeFullReload', () => {
    console.log('Full reload')
  })
  
  import.meta.hot.on('vite:error', (error) => {
    console.error('HMR error', error)
  })
  
  import.meta.hot.on('vite:ws:connect', () => {
    console.log('WebSocket connected')
  })
  
  import.meta.hot.on('vite:ws:disconnect', () => {
    console.log('WebSocket disconnected')
  })
}

Custom Events

Send events to server:

// Client
if (import.meta.hot) {
  import.meta.hot.send('my:event', { msg: 'Hello from client' })
}

Receive from server:

// Client
if (import.meta.hot) {
  import.meta.hot.on('my:response', (data) => {
    console.log(data.msg)
  })
}

TypeScript for Custom Events

// events.d.ts
import 'vite/types/customEvent.d.ts'

declare module 'vite/types/customEvent.d.ts' {
  interface CustomEventMap {
    'my:event': { msg: string }
    'my:response': { msg: string }
  }
}