CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-vite-node

Vite as Node.js runtime that enables on-demand evaluation with full ESM and TypeScript support

Pending
Overview
Eval results
Files

hmr.mddocs/

Hot Module Replacement

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.

Capabilities

HMR Context Management

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);
  });
}

HMR Message Handling

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);
});

Module Reloading

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);
});

HMR Cache Management

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;
}

Message Buffer Management

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;

HMR Emitter

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 Integration

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 Event Types

HMR supports various event types for different update scenarios:

Connected Event

Triggered when HMR connection is established.

Update Event

Handles JavaScript module updates with dependency tracking.

Full Reload Event

Triggers complete application reload when necessary.

Custom Event

Supports custom application-specific HMR events.

Prune Event

Handles cleanup when modules are removed.

Error Event

Handles and displays HMR-related errors.

Usage Patterns

Basic HMR Setup

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);
});

Module-level HMR

// 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;
}

Error Handling

HMR includes comprehensive error handling:

  • Update Failures: Graceful handling when hot updates fail
  • Connection Issues: Automatic reconnection and message buffering
  • Module Errors: Clear error reporting with source maps
  • Circular Dependencies: Detection and safe 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);
  }
});

Performance Considerations

HMR is optimized for development performance:

  • Incremental Updates: Only affected modules are reloaded
  • Dependency Tracking: Smart invalidation of dependent modules
  • Message Buffering: Prevents loss of updates during brief disconnections
  • Lazy Evaluation: Updates are queued and batched for efficiency

Install with Tessl CLI

npx tessl i tessl/npm-vite-node

docs

cli.md

client.md

hmr.md

index.md

server.md

source-maps.md

utils.md

tile.json