Fast Rust-based web bundler with webpack-compatible API
—
Development-time module replacement system for fast iteration without losing application state, with full webpack compatibility.
The main HMR API exposed through module.hot when HMR is enabled.
interface Hot {
/** Accept module updates with optional callback and error handling */
accept: {
/** Accept specific modules with callback for handling updates */
(
modules: string | string[],
callback?: (outdatedDependencies: string[]) => void,
errorHandler?: (
err: Error,
context: { moduleId: string | number; dependencyId: string | number }
) => void
): void;
/** Accept self updates with error handling */
(
errorHandler?: (
err: Error,
ids: { moduleId: string | number; module: NodeJS.Module }
) => void
): void;
};
/** Get current HMR status */
status(): HotUpdateStatus;
/** Decline updates for specific modules */
decline(module?: string | string[]): void;
/** Register callback for module disposal */
dispose(callback: (data: any) => void): void;
/** Add disposal handler */
addDisposeHandler(callback: (data: any) => void): void;
/** Remove disposal handler */
removeDisposeHandler(callback: (data: any) => void): void;
/** Invalidate current module */
invalidate(): void;
/** Add status change handler */
addStatusHandler(callback: (status: HotUpdateStatus) => void): void;
/** Remove status change handler */
removeStatusHandler(callback: (status: HotUpdateStatus) => void): void;
/** Data storage between updates */
data: any;
/** Check for available updates */
check(autoApply?: boolean | ApplyOptions): Promise<(string | number)[] | null>;
/** Apply pending updates */
apply(options?: ApplyOptions): Promise<(string | number)[] | null>;
}
/** HMR status values indicating current state */
type HotUpdateStatus = "idle" | "check" | "prepare" | "ready" | "dispose" | "apply" | "abort" | "fail";Usage Examples:
// Basic self-acceptance
if (module.hot) {
module.hot.accept((err) => {
if (err) {
console.error("Cannot accept update:", err);
}
});
}
// Accept specific dependencies
if (module.hot) {
module.hot.accept("./utils", (outdatedDependencies) => {
console.log("Utils module updated:", outdatedDependencies);
// Re-import and use updated utils
import("./utils").then((newUtils) => {
// Update application state with new utils
});
});
}
// Accept multiple dependencies with error handling
if (module.hot) {
module.hot.accept(
["./component-a", "./component-b"],
(outdatedDependencies) => {
console.log("Components updated:", outdatedDependencies);
},
(err, context) => {
console.error("Update failed:", err, context);
}
);
}
// Data persistence across updates
if (module.hot) {
// Save state before disposal
module.hot.dispose((data) => {
data.currentUser = getCurrentUser();
data.preferences = getPreferences();
});
// Restore state after update
if (module.hot.data) {
setCurrentUser(module.hot.data.currentUser);
setPreferences(module.hot.data.preferences);
}
}
// Status monitoring
if (module.hot) {
module.hot.addStatusHandler((status) => {
console.log("HMR Status:", status);
if (status === "apply") {
console.log("Applying updates...");
} else if (status === "fail") {
console.error("HMR update failed");
}
});
}Options for controlling update application behavior.
interface ApplyOptions {
/** Ignore modules that declined the update */
ignoreUnaccepted?: boolean;
/** Ignore modules that were declined by dependencies */
ignoreDeclined?: boolean;
/** Ignore modules that errored during update */
ignoreErrored?: boolean;
/** Handler for declined events */
onDeclined?: (event: DeclinedEvent) => void;
/** Handler for unaccepted events */
onUnaccepted?: (event: UnacceptedEvent) => void;
/** Handler for accepted events */
onAccepted?: (event: AcceptedEvent) => void;
/** Handler for disposed events */
onDisposed?: (event: DisposedEvent) => void;
/** Handler for error events */
onErrored?: (event: ErroredEvent) => void;
}Detailed event types for different HMR scenarios.
/** Module update was successfully accepted */
interface AcceptedEvent {
type: "accepted";
/** The module that was updated */
moduleId: string | number;
/** Modules that became outdated */
outdatedModules: (string | number)[];
/** Dependencies that became outdated */
outdatedDependencies: { [id: number]: (string | number)[] };
}
/** Module update was declined */
type DeclinedEvent =
| {
type: "declined";
/** The module in question */
moduleId: string | number;
/** Update propagation chain */
chain: (string | number)[];
/** Module that declined the update */
parentId: string | number;
}
| {
type: "self-declined";
/** The module in question */
moduleId: string | number;
/** Update propagation chain */
chain: (string | number)[];
};
/** Module update was not accepted */
interface UnacceptedEvent {
type: "unaccepted";
/** The module in question */
moduleId: string | number;
/** Update propagation chain */
chain: (string | number)[];
}
/** Module was disposed */
interface DisposedEvent {
type: "disposed";
/** The module that was disposed */
moduleId: string | number;
}
/** Error occurred during HMR process */
type ErroredEvent =
| {
type: "accept-error-handler-errored";
/** The module in question */
moduleId: string | number;
/** Module owning the error handler */
dependencyId: string | number;
/** The error that occurred */
error: Error;
/** Original error that triggered the handler */
originalError: Error;
}
| {
type: "self-accept-error-handler-errored";
/** The module in question */
moduleId: string | number;
/** The error that occurred */
error: Error;
/** Original error that triggered the handler */
originalError: Error;
}
| {
type: "accept-errored";
/** The module in question */
moduleId: string | number;
/** Module owning the accept handler */
dependencyId: string | number;
/** The error that occurred */
error: Error;
}
| {
type: "self-accept-errored";
/** The module in question */
moduleId: string | number;
/** The error that occurred */
error: Error;
};
/** Union of all HMR event types */
type HotEvent = AcceptedEvent | DeclinedEvent | UnacceptedEvent | DisposedEvent | ErroredEvent;HMR support for ES modules via import.meta.
interface ImportMeta {
/** HMR interface for ES modules (same as module.hot) */
webpackHot: Hot;
/** Base URL of the module */
url: string;
/** Webpack context function */
webpackContext: (
request: string,
options?: {
recursive?: boolean;
regExp?: RegExp;
include?: RegExp;
exclude?: RegExp;
preload?: boolean | number;
prefetch?: boolean | number;
fetchPriority?: "low" | "high" | "auto";
chunkName?: string;
exports?: string | string[][];
mode?: "sync" | "eager" | "weak" | "lazy" | "lazy-once";
}
) => any;
}ES Modules Usage:
// ES modules HMR
if (import.meta.webpackHot) {
import.meta.webpackHot.accept("./dependency", () => {
console.log("Dependency hot-reloaded");
});
}Client-side runtime files for different HMR integration scenarios.
/** WebSocket-based HMR client for webpack-dev-server */
declare module "@rspack/core/hot/dev-server" {
// Automatically connects to dev server
}
/** Enhanced dev-server client with better error handling */
declare module "@rspack/core/hot/only-dev-server" {
// Only hot reloads, no page refresh on errors
}
/** Polling-based HMR client */
declare module "@rspack/core/hot/poll" {
// Polls for updates periodically
}
/** Signal-based HMR client for Node.js */
declare module "@rspack/core/hot/signal" {
// Uses process signals for updates
}
/** HMR logging utility */
declare module "@rspack/core/hot/log" {
export function setLogLevel(level: "info" | "warning" | "error" | "none"): void;
export function info(...args: any[]): void;
export function warning(...args: any[]): void;
export function error(...args: any[]): void;
}
/** Event emitter for HMR events */
declare module "@rspack/core/hot/emitter" {
interface EventEmitter {
on(event: string, listener: (...args: any[]) => void): this;
emit(event: string, ...args: any[]): boolean;
}
const emitter: EventEmitter;
export default emitter;
}Plugin for enabling Hot Module Replacement.
/** Enable HMR functionality */
class HotModuleReplacementPlugin extends RspackBuiltinPlugin {
name: "HotModuleReplacementPlugin";
/** No configuration options needed */
constructor();
}Plugin Usage:
import { HotModuleReplacementPlugin } from "@rspack/core";
const config = {
mode: "development",
devServer: {
hot: true
},
plugins: [
new HotModuleReplacementPlugin()
]
};Common patterns for effective HMR integration.
// React component HMR
if (module.hot) {
module.hot.accept("./App", () => {
const NextApp = require("./App").default;
render(<NextApp />, document.getElementById("root"));
});
}
// Redux store HMR
if (module.hot) {
module.hot.accept("./reducers", () => {
const nextRootReducer = require("./reducers").default;
store.replaceReducer(nextRootReducer);
});
}
// CSS HMR with extraction
if (module.hot) {
module.hot.accept("./styles.css", () => {
// CSS is automatically reloaded by CssExtractRspackPlugin
});
}
// Manual update checking
if (module.hot) {
const checkForUpdates = async () => {
try {
const outdatedModules = await module.hot.check(false);
if (outdatedModules) {
console.log("Updates available:", outdatedModules);
const result = await module.hot.apply({
ignoreUnaccepted: true,
onAccepted: (event) => {
console.log("Module accepted:", event.moduleId);
}
});
console.log("Updates applied:", result);
}
} catch (err) {
console.error("Update failed:", err);
}
};
// Check for updates every 10 seconds
setInterval(checkForUpdates, 10000);
}Install with Tessl CLI
npx tessl i tessl/npm-rspack--core