import type { HMRPayload, Plugin } from 'vite' import { EventEmitter } from 'node:events' export type EventType = string | symbol export type Handler = (event: T) => void export interface Emitter> { on: ( type: Key, handler: Handler ) => void off: ( type: Key, handler?: Handler ) => void emit: ((type: Key, event: Events[Key]) => void) & (( type: undefined extends Events[Key] ? Key : never ) => void) } export type HMREmitter = Emitter<{ message: HMRPayload }> & EventEmitter declare module 'vite' { interface ViteDevServer { emitter: HMREmitter } } export function createHmrEmitter(): HMREmitter { const emitter = new EventEmitter() return emitter as HMREmitter } export function viteNodeHmrPlugin(): Plugin { const emitter = createHmrEmitter() return { name: 'vite-node:hmr', config() { // chokidar fsevents is unstable on macos when emitting "ready" event if ( process.platform === 'darwin' && process.env.VITE_TEST_WATCHER_DEBUG ) { return { server: { watch: { useFsEvents: false, usePolling: false, }, }, } } }, configureServer(server) { const _send = server.ws.send server.emitter = emitter server.ws.send = function (payload: any) { _send(payload) emitter.emit('message', payload) } // eslint-disable-next-line ts/ban-ts-comment // @ts-ignore Vite 6 compat const environments = server.environments if (environments) { environments.ssr.hot.send = function (payload: any) { _send(payload) emitter.emit('message', payload) } } }, } }