0
# Hot Module Replacement
1
2
Development-time module replacement system for fast iteration without losing application state, with full webpack compatibility.
3
4
## Capabilities
5
6
### Core HMR Interface
7
8
The main HMR API exposed through `module.hot` when HMR is enabled.
9
10
```typescript { .api }
11
interface Hot {
12
/** Accept module updates with optional callback and error handling */
13
accept: {
14
/** Accept specific modules with callback for handling updates */
15
(
16
modules: string | string[],
17
callback?: (outdatedDependencies: string[]) => void,
18
errorHandler?: (
19
err: Error,
20
context: { moduleId: string | number; dependencyId: string | number }
21
) => void
22
): void;
23
24
/** Accept self updates with error handling */
25
(
26
errorHandler?: (
27
err: Error,
28
ids: { moduleId: string | number; module: NodeJS.Module }
29
) => void
30
): void;
31
};
32
33
/** Get current HMR status */
34
status(): HotUpdateStatus;
35
36
/** Decline updates for specific modules */
37
decline(module?: string | string[]): void;
38
39
/** Register callback for module disposal */
40
dispose(callback: (data: any) => void): void;
41
42
/** Add disposal handler */
43
addDisposeHandler(callback: (data: any) => void): void;
44
45
/** Remove disposal handler */
46
removeDisposeHandler(callback: (data: any) => void): void;
47
48
/** Invalidate current module */
49
invalidate(): void;
50
51
/** Add status change handler */
52
addStatusHandler(callback: (status: HotUpdateStatus) => void): void;
53
54
/** Remove status change handler */
55
removeStatusHandler(callback: (status: HotUpdateStatus) => void): void;
56
57
/** Data storage between updates */
58
data: any;
59
60
/** Check for available updates */
61
check(autoApply?: boolean | ApplyOptions): Promise<(string | number)[] | null>;
62
63
/** Apply pending updates */
64
apply(options?: ApplyOptions): Promise<(string | number)[] | null>;
65
}
66
67
/** HMR status values indicating current state */
68
type HotUpdateStatus = "idle" | "check" | "prepare" | "ready" | "dispose" | "apply" | "abort" | "fail";
69
```
70
71
**Usage Examples:**
72
73
```typescript
74
// Basic self-acceptance
75
if (module.hot) {
76
module.hot.accept((err) => {
77
if (err) {
78
console.error("Cannot accept update:", err);
79
}
80
});
81
}
82
83
// Accept specific dependencies
84
if (module.hot) {
85
module.hot.accept("./utils", (outdatedDependencies) => {
86
console.log("Utils module updated:", outdatedDependencies);
87
// Re-import and use updated utils
88
import("./utils").then((newUtils) => {
89
// Update application state with new utils
90
});
91
});
92
}
93
94
// Accept multiple dependencies with error handling
95
if (module.hot) {
96
module.hot.accept(
97
["./component-a", "./component-b"],
98
(outdatedDependencies) => {
99
console.log("Components updated:", outdatedDependencies);
100
},
101
(err, context) => {
102
console.error("Update failed:", err, context);
103
}
104
);
105
}
106
107
// Data persistence across updates
108
if (module.hot) {
109
// Save state before disposal
110
module.hot.dispose((data) => {
111
data.currentUser = getCurrentUser();
112
data.preferences = getPreferences();
113
});
114
115
// Restore state after update
116
if (module.hot.data) {
117
setCurrentUser(module.hot.data.currentUser);
118
setPreferences(module.hot.data.preferences);
119
}
120
}
121
122
// Status monitoring
123
if (module.hot) {
124
module.hot.addStatusHandler((status) => {
125
console.log("HMR Status:", status);
126
127
if (status === "apply") {
128
console.log("Applying updates...");
129
} else if (status === "fail") {
130
console.error("HMR update failed");
131
}
132
});
133
}
134
```
135
136
### HMR Configuration Options
137
138
Options for controlling update application behavior.
139
140
```typescript { .api }
141
interface ApplyOptions {
142
/** Ignore modules that declined the update */
143
ignoreUnaccepted?: boolean;
144
/** Ignore modules that were declined by dependencies */
145
ignoreDeclined?: boolean;
146
/** Ignore modules that errored during update */
147
ignoreErrored?: boolean;
148
/** Handler for declined events */
149
onDeclined?: (event: DeclinedEvent) => void;
150
/** Handler for unaccepted events */
151
onUnaccepted?: (event: UnacceptedEvent) => void;
152
/** Handler for accepted events */
153
onAccepted?: (event: AcceptedEvent) => void;
154
/** Handler for disposed events */
155
onDisposed?: (event: DisposedEvent) => void;
156
/** Handler for error events */
157
onErrored?: (event: ErroredEvent) => void;
158
}
159
```
160
161
### HMR Event Types
162
163
Detailed event types for different HMR scenarios.
164
165
```typescript { .api }
166
/** Module update was successfully accepted */
167
interface AcceptedEvent {
168
type: "accepted";
169
/** The module that was updated */
170
moduleId: string | number;
171
/** Modules that became outdated */
172
outdatedModules: (string | number)[];
173
/** Dependencies that became outdated */
174
outdatedDependencies: { [id: number]: (string | number)[] };
175
}
176
177
/** Module update was declined */
178
type DeclinedEvent =
179
| {
180
type: "declined";
181
/** The module in question */
182
moduleId: string | number;
183
/** Update propagation chain */
184
chain: (string | number)[];
185
/** Module that declined the update */
186
parentId: string | number;
187
}
188
| {
189
type: "self-declined";
190
/** The module in question */
191
moduleId: string | number;
192
/** Update propagation chain */
193
chain: (string | number)[];
194
};
195
196
/** Module update was not accepted */
197
interface UnacceptedEvent {
198
type: "unaccepted";
199
/** The module in question */
200
moduleId: string | number;
201
/** Update propagation chain */
202
chain: (string | number)[];
203
}
204
205
/** Module was disposed */
206
interface DisposedEvent {
207
type: "disposed";
208
/** The module that was disposed */
209
moduleId: string | number;
210
}
211
212
/** Error occurred during HMR process */
213
type ErroredEvent =
214
| {
215
type: "accept-error-handler-errored";
216
/** The module in question */
217
moduleId: string | number;
218
/** Module owning the error handler */
219
dependencyId: string | number;
220
/** The error that occurred */
221
error: Error;
222
/** Original error that triggered the handler */
223
originalError: Error;
224
}
225
| {
226
type: "self-accept-error-handler-errored";
227
/** The module in question */
228
moduleId: string | number;
229
/** The error that occurred */
230
error: Error;
231
/** Original error that triggered the handler */
232
originalError: Error;
233
}
234
| {
235
type: "accept-errored";
236
/** The module in question */
237
moduleId: string | number;
238
/** Module owning the accept handler */
239
dependencyId: string | number;
240
/** The error that occurred */
241
error: Error;
242
}
243
| {
244
type: "self-accept-errored";
245
/** The module in question */
246
moduleId: string | number;
247
/** The error that occurred */
248
error: Error;
249
};
250
251
/** Union of all HMR event types */
252
type HotEvent = AcceptedEvent | DeclinedEvent | UnacceptedEvent | DisposedEvent | ErroredEvent;
253
```
254
255
### ES Modules HMR Support
256
257
HMR support for ES modules via `import.meta`.
258
259
```typescript { .api }
260
interface ImportMeta {
261
/** HMR interface for ES modules (same as module.hot) */
262
webpackHot: Hot;
263
/** Base URL of the module */
264
url: string;
265
/** Webpack context function */
266
webpackContext: (
267
request: string,
268
options?: {
269
recursive?: boolean;
270
regExp?: RegExp;
271
include?: RegExp;
272
exclude?: RegExp;
273
preload?: boolean | number;
274
prefetch?: boolean | number;
275
fetchPriority?: "low" | "high" | "auto";
276
chunkName?: string;
277
exports?: string | string[][];
278
mode?: "sync" | "eager" | "weak" | "lazy" | "lazy-once";
279
}
280
) => any;
281
}
282
```
283
284
**ES Modules Usage:**
285
286
```typescript
287
// ES modules HMR
288
if (import.meta.webpackHot) {
289
import.meta.webpackHot.accept("./dependency", () => {
290
console.log("Dependency hot-reloaded");
291
});
292
}
293
```
294
295
### HMR Client Runtime
296
297
Client-side runtime files for different HMR integration scenarios.
298
299
```typescript { .api }
300
/** WebSocket-based HMR client for webpack-dev-server */
301
declare module "@rspack/core/hot/dev-server" {
302
// Automatically connects to dev server
303
}
304
305
/** Enhanced dev-server client with better error handling */
306
declare module "@rspack/core/hot/only-dev-server" {
307
// Only hot reloads, no page refresh on errors
308
}
309
310
/** Polling-based HMR client */
311
declare module "@rspack/core/hot/poll" {
312
// Polls for updates periodically
313
}
314
315
/** Signal-based HMR client for Node.js */
316
declare module "@rspack/core/hot/signal" {
317
// Uses process signals for updates
318
}
319
320
/** HMR logging utility */
321
declare module "@rspack/core/hot/log" {
322
export function setLogLevel(level: "info" | "warning" | "error" | "none"): void;
323
export function info(...args: any[]): void;
324
export function warning(...args: any[]): void;
325
export function error(...args: any[]): void;
326
}
327
328
/** Event emitter for HMR events */
329
declare module "@rspack/core/hot/emitter" {
330
interface EventEmitter {
331
on(event: string, listener: (...args: any[]) => void): this;
332
emit(event: string, ...args: any[]): boolean;
333
}
334
335
const emitter: EventEmitter;
336
export default emitter;
337
}
338
```
339
340
### HMR Plugin Configuration
341
342
Plugin for enabling Hot Module Replacement.
343
344
```typescript { .api }
345
/** Enable HMR functionality */
346
class HotModuleReplacementPlugin extends RspackBuiltinPlugin {
347
name: "HotModuleReplacementPlugin";
348
/** No configuration options needed */
349
constructor();
350
}
351
```
352
353
**Plugin Usage:**
354
355
```typescript
356
import { HotModuleReplacementPlugin } from "@rspack/core";
357
358
const config = {
359
mode: "development",
360
devServer: {
361
hot: true
362
},
363
plugins: [
364
new HotModuleReplacementPlugin()
365
]
366
};
367
```
368
369
### Advanced HMR Patterns
370
371
Common patterns for effective HMR integration.
372
373
```typescript
374
// React component HMR
375
if (module.hot) {
376
module.hot.accept("./App", () => {
377
const NextApp = require("./App").default;
378
render(<NextApp />, document.getElementById("root"));
379
});
380
}
381
382
// Redux store HMR
383
if (module.hot) {
384
module.hot.accept("./reducers", () => {
385
const nextRootReducer = require("./reducers").default;
386
store.replaceReducer(nextRootReducer);
387
});
388
}
389
390
// CSS HMR with extraction
391
if (module.hot) {
392
module.hot.accept("./styles.css", () => {
393
// CSS is automatically reloaded by CssExtractRspackPlugin
394
});
395
}
396
397
// Manual update checking
398
if (module.hot) {
399
const checkForUpdates = async () => {
400
try {
401
const outdatedModules = await module.hot.check(false);
402
if (outdatedModules) {
403
console.log("Updates available:", outdatedModules);
404
const result = await module.hot.apply({
405
ignoreUnaccepted: true,
406
onAccepted: (event) => {
407
console.log("Module accepted:", event.moduleId);
408
}
409
});
410
console.log("Updates applied:", result);
411
}
412
} catch (err) {
413
console.error("Update failed:", err);
414
}
415
};
416
417
// Check for updates every 10 seconds
418
setInterval(checkForUpdates, 10000);
419
}
420
```