Vite as Node.js runtime that enables on-demand evaluation with full ESM and TypeScript support
—
Complete HMR implementation with event handling, module invalidation, and hot context management for development workflows. Provides seamless hot reloading capabilities for Node.js applications during development.
Create and manage hot contexts for modules to handle hot updates.
/**
* Create a hot context for a module to handle HMR updates
* Provides accept, dispose, and invalidate functionality
*/
function createHotContext(
runner: ViteNodeRunner,
emitter: HMREmitter,
files: string[],
ownerPath: string
): HotContext;
interface HotContext {
/** Module-specific data that persists across hot updates */
data: any;
/** Accept hot updates for this module or its dependencies */
accept(deps?: string | string[] | ((mod: any) => void), callback?: (mod: any) => void): void;
/** Accept updates for specific exports */
acceptExports(exports?: string | string[], callback?: (mod: any) => void): void;
/** Register cleanup function called before module is updated */
dispose(callback: (data: any) => void): void;
/** Register cleanup function called when module is pruned */
prune(callback: (data: any) => void): void;
/** Invalidate this module and trigger a full reload */
invalidate(): Promise<any[]>;
/** Listen for custom HMR events */
on<T extends string>(event: T, callback: (payload: any) => void): void;
/** Remove listener for custom HMR events */
off<T extends string>(event: T, callback: (payload: any) => void): void;
/** Send custom HMR event */
send<T extends string>(event: T, data?: any): void;
}Usage Examples:
// In a module that needs HMR support
if (import.meta.hot) {
import.meta.hot.accept((newModule) => {
// Handle hot update
console.log('Module updated', newModule);
});
import.meta.hot.dispose((data) => {
// Clean up before update
data.cleanup?.();
});
import.meta.hot.on('custom-event', (data) => {
// Handle custom HMR events
console.log('Custom event received', data);
});
}Handle HMR messages and coordinate updates across the system.
/**
* Handle HMR messages from Vite and coordinate appropriate responses
* Supports update, full-reload, error, and custom message types
*/
function handleMessage(
runner: ViteNodeRunner,
emitter: HMREmitter,
files: string[],
payload: HMRPayload
): Promise<void>;Usage Examples:
import { handleMessage } from "vite-node/hmr";
// Set up HMR message handling
server.emitter?.on('message', (payload) => {
handleMessage(runner, server.emitter, files, payload);
});Reload modules and handle cache invalidation during hot updates.
/**
* Reload specified files and invalidate their cache entries
* Preserves node_modules cache while clearing application modules
*/
function reload(runner: ViteNodeRunner, files: string[]): Promise<any[]>;Usage Examples:
import { reload } from "vite-node/hmr";
// Reload specific files
const results = await reload(runner, ['./src/app.ts', './src/utils.ts']);
// Handle reload results
results.forEach((result, index) => {
console.log(`Reloaded ${files[index]}:`, result);
});Access and manage HMR-related cache data.
/**
* Get HMR cache data for a runner instance
* Includes hot modules, data, dispose callbacks, and message buffers
*/
function getCache(runner: ViteNodeRunner): CacheData;
interface CacheData {
hotModulesMap: Map<string, HotModule>;
dataMap: Map<string, any>;
disposeMap: Map<string, (data: any) => void | Promise<void>>;
pruneMap: Map<string, (data: any) => void | Promise<void>>;
customListenersMap: Map<string, ((data: any) => void)[]>;
ctxToListenersMap: Map<string, Map<string, ((data: any) => void)[]>>;
messageBuffer: string[];
isFirstUpdate: boolean;
pending: boolean;
queued: Promise<(() => void) | undefined>[];
}
interface HotModule {
id: string;
callbacks: HotCallback[];
}
interface HotCallback {
deps: string[];
fn: (modules: (ModuleNamespace | undefined)[]) => void;
}Manage buffered HMR messages for reliable delivery.
/**
* Send buffered messages to HMR emitter
* Ensures messages are delivered even if connection is temporarily unavailable
*/
function sendMessageBuffer(runner: ViteNodeRunner, emitter: HMREmitter): void;Event emitter for HMR communication between server and clients.
/**
* Create HMR emitter for handling hot update events
* Extends EventEmitter with HMR-specific message handling
*/
function createHmrEmitter(): HMREmitter;
interface HMREmitter extends EventEmitter {
on(event: 'message', handler: (payload: HMRPayload) => void): void;
emit(event: 'message', payload: HMRPayload): void;
}Vite plugin for integrating HMR functionality.
/**
* Vite plugin that enables HMR functionality for vite-node
* Configures server settings and message handling
*/
function viteNodeHmrPlugin(): Plugin;Usage Examples:
import { viteNodeHmrPlugin } from "vite-node/hmr";
const server = await createServer({
plugins: [
viteNodeHmrPlugin(),
// other plugins...
],
});HMR supports various event types for different update scenarios:
Triggered when HMR connection is established.
Handles JavaScript module updates with dependency tracking.
Triggers complete application reload when necessary.
Supports custom application-specific HMR events.
Handles cleanup when modules are removed.
Handles and displays HMR-related errors.
import { createServer } from "vite";
import { ViteNodeRunner } from "vite-node/client";
import { ViteNodeServer } from "vite-node/server";
import { createHotContext, handleMessage, viteNodeHmrPlugin } from "vite-node/hmr";
// Create Vite server with HMR support
const server = await createServer({
plugins: [viteNodeHmrPlugin()],
server: { hmr: true },
});
// Create vite-node components
const nodeServer = new ViteNodeServer(server);
const runner = new ViteNodeRunner({
root: server.config.root,
fetchModule: (id) => nodeServer.fetchModule(id),
resolveId: (id, importer) => nodeServer.resolveId(id, importer),
createHotContext: (runner, url) => createHotContext(runner, server.emitter, files, url),
});
// Handle HMR messages
server.emitter?.on('message', (payload) => {
handleMessage(runner, server.emitter, files, payload);
});// In your application modules
declare global {
interface ImportMeta {
hot?: {
accept: (callback?: (newModule: any) => void) => void;
dispose: (callback: (data: any) => void) => void;
data: any;
};
}
}
// Use HMR in modules
if (import.meta.hot) {
// Accept updates to this module
import.meta.hot.accept((newModule) => {
console.log('Module hot updated');
});
// Cleanup before update
import.meta.hot.dispose((data) => {
// Store state for next version
data.state = getCurrentState();
});
// Access preserved data
const previousState = import.meta.hot.data.state;
}HMR includes comprehensive error handling:
Common error handling patterns:
// Handle HMR errors
server.emitter?.on('message', async (payload) => {
try {
await handleMessage(runner, server.emitter, files, payload);
} catch (error) {
console.error('HMR update failed:', error);
// Optionally trigger full reload
await reload(runner, files);
}
});HMR is optimized for development performance: