Hot module replacement
Rspack provides the same interface as webpack for implementing HMR.
If you've enabled Hot Module Replacement via the HotModuleReplacementPlugin, its interface is exposed on the module.hot and import.meta.webpackHot objects.
In ESM, use import.meta.webpackHot instead of module.hot.
Example
To accept updates to a module you have already loaded, first check whether the HMR interface is available:
Update propagation
When a module changes, Rspack checks whether the update can be handled without reloading the page. A module can accept its own update with accept(), or an importing module can accept updates to that dependency with accept(dependency, callback). Otherwise, the update continues to the modules that import it.
For example, consider this chain of imports:
When button.js changes:
- If
view.jsaccepts updates tobutton.js, Rspack replacesbutton.jsand calls the callback inview.js. It does not replaceview.jsorapp.js. - If only
app.jsaccepts updates toview.js, Rspack replaces bothbutton.jsandview.js, then calls the callback inapp.js.
If there are multiple importers, every affected path must accept the update. By default, an update is aborted if a module declines it or it reaches an entry module without being accepted. The dev server can then fall back to a full page reload.
Module API
The following methods are supported by module.hot and import.meta.webpackHot.
accept
Accepts updates for the given dependencies and fires a callback to handle those updates. You can also attach an optional error handler:
When using ESM import, all imported symbols from dependencies are automatically updated. Note: The dependency string must exactly match the from string in the import. In some cases, callback can be omitted. Using require() in the callback isn't useful here.
When using CommonJS, update dependencies manually using require() in the callback. Omitting the callback isn't useful here.
errorHandler for accept
(err, {moduleId, dependencyId}) => {}
err: The error thrown by the callback in the second argument or during dependency execution when using ESM dependencies.moduleId: The current module ID.dependencyId: The module ID of the (first) changed dependency.
accept (self)
Accepts updates for itself.
When this module or its dependencies are updated, it can be disposed and re-evaluated without notifying parents. This makes sense if the module has no exports (or exports are updated in another way).
The errorHandler fires when evaluating this module (or its dependencies) throws an exception.
errorHandler for self accept
(err, {moduleId, module}) => {}
err: The error when evaluating the new version.moduleId: The current module ID.module: The current module instance.module.hot: Allows using the HMR API of the errored module instance. A common scenario is to self-accept it again. It also makes sense to add a dispose handler to pass data along. Note that the errored module might already be partially executed, so avoid getting into an inconsistent state. Usemodule.hot.datato store partial state.module.exports: Can be overridden, but be careful since property names might be mangled in production mode.
decline
Rejects updates for the given dependencies, forcing the update to fail with a 'decline' code.
Flags a dependency as not updatable. This makes sense when changes to this dependency's exports can't be handled or handling isn't implemented yet. Depending on your HMR management code, updates to these dependencies (or their unaccepted dependencies) usually cause a full page reload.
decline (self)
Rejects updates for itself.
Flag this module as not-update-able. This makes sense when this module has irreversible side-effects, or HMR handling is not implemented for this module yet. Depending on your HMR management code, an update to this module (or unaccepted dependencies) usually causes a full-reload of the page.
dispose (or addDisposeHandler)
Register a handler to clean up resources, such as timers or event listeners, before the module is replaced. Store any state you want to preserve on the data argument; the updated module can read it from import.meta.webpackHot.data (or module.hot.data for CommonJS).
This example clears the old timer and resumes counting from the saved value after an update:
invalidate
Call invalidate() when the current module cannot handle a hot update and needs the modules that import it to handle the update instead. The update propagates to those modules even if the current module previously called accept() to accept its own updates. See Update propagation.
When applying an accepted update, Rspack first calls the current module's dispose handlers to clean up its resources.
To reject updates to the current module, use decline().
When called during the idle state, a new HMR update will be created containing this module. HMR will enter the ready state.
When called during the ready or prepare state, this module will be added to the current HMR update.
When called during the check state, this module will be added to the update when an update is available. If no update is available it will create a new update. HMR will enter the ready state.
When called during the dispose or apply state, HMR will pick it up after getting out of those states.
Use cases
When a dependency update cannot be handled
Inside an accept() callback, call invalidate() if the current module cannot handle the dependency's update. This lets modules that import the current module handle the update:
When a module cannot handle its own update
The following module accepts its own updates and compares the new exported string with the previous one. If the string changes, it calls invalidate() so that modules importing it can also update:
- In a
disposecallback, write any data you want to keep to thedataobject. The updated module can read it fromimport.meta.webpackHot.data(module.hot.datain CommonJS). - On first execution, no previous state is available, so this value is
undefined. After an update, it is an empty object if the previous version did not save any data. - Do not call
invalidate()every time the module runs. Doing so can make each hot update trigger another, creating an update loop.
removeDisposeHandler
Remove the handler added via dispose or addDisposeHandler.
Management API
status
Retrieve the current status of the hot module replacement process.
check
Check for hot updates and download any that are available. HMR must be in the idle state when you call this method.
Use autoApply to choose whether to apply the update as soon as it finishes downloading:
- Omitted or
false: download the update and enter thereadystate. Callapply()when you are ready to apply it. true: apply the update immediately after downloading it.- An options object: apply the update immediately, using the object as the
apply()options.
The .then() callback receives an array of module IDs involved in the update, or null if no update is available. Errors while downloading or applying the update can be handled in .catch().
apply
Continue the update process (as long as module.hot.status() === 'ready').
The optional options object can include the following properties:
ignoreUnaccepted(boolean): Ignore changes made to unaccepted modules.ignoreDeclined(boolean): Ignore changes made to declined modules.ignoreErrored(boolean): Ignore errors thrown in accept handlers, error handlers and while reevaluating module.onDeclined(function(info)): Notifier for declined modulesonUnaccepted(function(info)): Notifier for unaccepted modulesonAccepted(function(info)): Notifier for accepted modulesonDisposed(function(info)): Notifier for disposed modulesonErrored(function(info)): Notifier for errors
The info parameter will be an object containing some of the following values:
For example, if app.js calls module.hot.accept('./button.js', callback) and callback throws when button.js is updated, moduleId is the ID of app.js, and dependencyId is the ID of button.js.
If the error handler then throws another error, type is 'accept-error-handler-errored', error is the new error, and originalError is the error thrown by callback.
addStatusHandler
Register a function to listen for changes in status.
Bear in mind that when the status handler returns a Promise, the HMR system will wait for the Promise to resolve before continuing.
removeStatusHandler
Remove a registered status handler.
This page is adapted from webpack documentation under the CC BY 4.0, with modifications.

