0
# Hot Module Replacement
1
2
Vite's Hot Module Replacement (HMR) system provides instant updates during development with WebSocket communication, client-server coordination, and comprehensive plugin integration for seamless development experience.
3
4
## Capabilities
5
6
### Server Hot Channel
7
8
Create server-side HMR channel for communication with clients.
9
10
```typescript { .api }
11
/**
12
* Create server hot channel for HMR communication
13
* @param server - Vite dev server (optional)
14
* @returns ServerHotChannel instance
15
*/
16
function createServerHotChannel(server?: ViteDevServer): ServerHotChannel;
17
18
interface ServerHotChannel extends HotChannel {
19
/** Send update to all clients */
20
send(payload: HotPayload): void;
21
/** Close channel */
22
close(): void;
23
/** Handle client connection */
24
on(event: 'connection', handler: (client: HotChannelClient) => void): void;
25
/** Handle client disconnect */
26
on(event: 'disconnect', handler: (client: HotChannelClient) => void): void;
27
}
28
```
29
30
**Usage Examples:**
31
32
```typescript
33
import { createServerHotChannel } from "vite";
34
35
// Create HMR channel
36
const hotChannel = createServerHotChannel(server);
37
38
// Send custom update
39
hotChannel.send({
40
type: 'custom',
41
event: 'my-plugin-update',
42
data: { message: 'Plugin state changed' }
43
});
44
45
// Listen for connections
46
hotChannel.on('connection', (client) => {
47
console.log('Client connected:', client.socket.id);
48
});
49
```
50
51
### HMR Configuration
52
53
Configure Hot Module Replacement behavior and WebSocket settings.
54
55
```typescript { .api }
56
interface HmrOptions {
57
/** HMR port (default: 24678) */
58
port?: number;
59
/** HMR host */
60
host?: string;
61
/** Client-side port override */
62
clientPort?: number;
63
/** Show error overlay */
64
overlay?: boolean;
65
/** HMR server */
66
server?: any;
67
}
68
69
interface HotUpdateOptions {
70
/** Update type */
71
type: 'js-update' | 'css-update' | 'full-reload';
72
/** Timestamp */
73
timestamp?: number;
74
/** Updates to apply */
75
updates?: Update[];
76
}
77
```
78
79
### HMR Payload Types
80
81
Types for different HMR messages sent between server and client.
82
83
```typescript { .api }
84
/**
85
* Union of all possible HMR payloads
86
*/
87
type HotPayload =
88
| ConnectedPayload
89
| UpdatePayload
90
| FullReloadPayload
91
| PrunePayload
92
| ErrorPayload
93
| CustomPayload;
94
95
interface ConnectedPayload {
96
type: 'connected';
97
}
98
99
interface UpdatePayload {
100
type: 'update';
101
updates: Update[];
102
}
103
104
interface Update {
105
/** Update type */
106
type: 'js-update' | 'css-update';
107
/** Module path */
108
path: string;
109
/** Update timestamp */
110
timestamp: number;
111
/** Accepted modules */
112
acceptedPath: string;
113
/** Explicit imports only */
114
explicitImportRequired?: boolean;
115
/** SSR error */
116
ssrError?: Error;
117
}
118
119
interface FullReloadPayload {
120
type: 'full-reload';
121
/** Reload trigger path */
122
path?: string;
123
}
124
125
interface PrunePayload {
126
type: 'prune';
127
/** Paths to prune */
128
paths: string[];
129
}
130
131
interface ErrorPayload {
132
type: 'error';
133
/** Error details */
134
err: {
135
message: string;
136
stack: string;
137
id?: string;
138
frame?: string;
139
plugin?: string;
140
pluginCode?: string;
141
loc?: {
142
file?: string;
143
line: number;
144
column: number;
145
};
146
};
147
}
148
149
interface CustomPayload {
150
type: 'custom';
151
/** Custom event name */
152
event: string;
153
/** Custom data */
154
data?: any;
155
}
156
```
157
158
**Usage Examples:**
159
160
```typescript
161
// Send different types of updates
162
const hotChannel = createServerHotChannel();
163
164
// JavaScript update
165
hotChannel.send({
166
type: 'update',
167
updates: [{
168
type: 'js-update',
169
path: '/src/components/Button.tsx',
170
timestamp: Date.now(),
171
acceptedPath: '/src/components/Button.tsx'
172
}]
173
});
174
175
// CSS update
176
hotChannel.send({
177
type: 'update',
178
updates: [{
179
type: 'css-update',
180
path: '/src/styles/main.css',
181
timestamp: Date.now(),
182
acceptedPath: '/src/styles/main.css'
183
}]
184
});
185
186
// Full reload
187
hotChannel.send({
188
type: 'full-reload',
189
path: '/vite.config.js'
190
});
191
192
// Custom event
193
hotChannel.send({
194
type: 'custom',
195
event: 'config-changed',
196
data: { newConfig: {...} }
197
});
198
```
199
200
### HMR Context
201
202
Context information provided to HMR handlers during hot updates.
203
204
```typescript { .api }
205
interface HmrContext {
206
/** File that changed */
207
file: string;
208
/** Change timestamp */
209
timestamp: number;
210
/** Affected module nodes */
211
modules: Set<ModuleNode>;
212
/** Read file contents */
213
read: () => string | Promise<string>;
214
/** Vite dev server */
215
server: ViteDevServer;
216
}
217
```
218
219
### WebSocket Server
220
221
WebSocket server interface for HMR communication.
222
223
```typescript { .api }
224
interface WebSocketServer {
225
/** Send message to all clients */
226
send(payload: HotPayload): void;
227
/** Send message to specific client */
228
send(client: WebSocketClient, payload: HotPayload): void;
229
/** Close server */
230
close(): Promise<void>;
231
/** Handle client connections */
232
on(event: 'connection', handler: (socket: WebSocketClient, request: any) => void): void;
233
/** Handle errors */
234
on(event: 'error', handler: (error: Error) => void): void;
235
}
236
237
interface WebSocketClient {
238
/** Send message to client */
239
send(data: string): void;
240
/** Close client connection */
241
close(): void;
242
/** Terminate connection */
243
terminate(): void;
244
/** Connection state */
245
readyState: number;
246
/** Client socket */
247
socket: any;
248
/** Handle messages */
249
on(event: 'message', handler: (data: any) => void): void;
250
/** Handle close */
251
on(event: 'close', handler: () => void): void;
252
/** Handle errors */
253
on(event: 'error', handler: (error: Error) => void): void;
254
}
255
256
interface WebSocketCustomListener<T = any> {
257
(data: T, client: WebSocketClient): void;
258
}
259
```
260
261
### Hot Channel Types
262
263
Normalized hot channel interfaces for consistent HMR communication.
264
265
```typescript { .api }
266
interface HotChannel {
267
/** Listen for events */
268
on(event: string, handler: HotChannelListener): void;
269
/** Remove event listener */
270
off(event: string, handler: HotChannelListener): void;
271
/** Send data */
272
send(data: any): void;
273
}
274
275
interface HotChannelClient {
276
/** Send data to client */
277
send(data: any): void;
278
/** Close client connection */
279
close(): void;
280
/** Underlying socket */
281
socket: any;
282
}
283
284
interface NormalizedHotChannel extends HotChannel {
285
/** Send payload */
286
send(payload: HotPayload): void;
287
}
288
289
interface NormalizedHotChannelClient extends HotChannelClient {
290
/** Send payload to client */
291
send(payload: HotPayload): void;
292
}
293
294
interface NormalizedServerHotChannel extends ServerHotChannel {
295
/** Send to all clients */
296
send(payload: HotPayload): void;
297
/** Send to specific client */
298
send(client: NormalizedHotChannelClient, payload: HotPayload): void;
299
}
300
301
type HotChannelListener = (data: any, client?: HotChannelClient) => void;
302
```
303
304
## HMR Integration Patterns
305
306
### Plugin HMR Support
307
308
Integrate HMR support in plugins for custom file types.
309
310
```typescript { .api }
311
// Plugin with HMR support
312
function myPlugin(): Plugin {
313
return {
314
name: 'my-plugin',
315
load(id) {
316
if (id.endsWith('.myext')) {
317
// Load custom file type
318
return `export default ${JSON.stringify(loadMyFile(id))}`;
319
}
320
},
321
handleHotUpdate(ctx) {
322
if (ctx.file.endsWith('.myext')) {
323
// Custom HMR logic for .myext files
324
ctx.server.ws.send({
325
type: 'custom',
326
event: 'myext-changed',
327
data: { file: ctx.file }
328
});
329
330
// Return empty array to prevent default HMR
331
return [];
332
}
333
}
334
};
335
}
336
```
337
338
### Client-Side HMR API
339
340
Client-side HMR API available in development.
341
342
```typescript { .api }
343
// Available in client code during development
344
interface ImportMeta {
345
hot?: {
346
/** Accept updates for this module */
347
accept(): void;
348
accept(cb: (newModule: any) => void): void;
349
accept(deps: string[], cb: (newModules: any[]) => void): void;
350
351
/** Decline updates for this module */
352
decline(): void;
353
354
/** Dispose callback when module is replaced */
355
dispose(cb: () => void): void;
356
357
/** Invalidate and force full reload */
358
invalidate(): void;
359
360
/** Register custom event listener */
361
on<T = any>(event: string, cb: (data: T) => void): void;
362
363
/** Send custom event to server */
364
send<T = any>(event: string, data?: T): void;
365
};
366
}
367
```
368
369
**Usage Examples:**
370
371
```typescript
372
// Component with HMR support
373
let count = 0;
374
375
export function Counter() {
376
return `<div>Count: ${count}</div>`;
377
}
378
379
// HMR boundary
380
if (import.meta.hot) {
381
import.meta.hot.accept((newModule) => {
382
// Handle module replacement
383
console.log('Counter updated');
384
});
385
386
import.meta.hot.dispose(() => {
387
// Cleanup before replacement
388
console.log('Cleaning up counter');
389
});
390
391
// Listen for custom events
392
import.meta.hot.on('reset-counter', () => {
393
count = 0;
394
updateUI();
395
});
396
}
397
```
398
399
### Error Handling
400
401
Handle HMR errors and recovery.
402
403
```typescript { .api }
404
// Error handling in plugins
405
function errorHandlingPlugin(): Plugin {
406
return {
407
name: 'error-handling',
408
handleHotUpdate(ctx) {
409
try {
410
// Process update
411
processUpdate(ctx.file);
412
} catch (error) {
413
// Send error to client
414
ctx.server.ws.send({
415
type: 'error',
416
err: {
417
message: error.message,
418
stack: error.stack,
419
id: ctx.file,
420
plugin: 'error-handling'
421
}
422
});
423
424
// Don't propagate error
425
return ctx.modules;
426
}
427
}
428
};
429
}
430
```