@rspack/plugin-react-refresh 1.5.0 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -217,6 +217,21 @@ new ReactRefreshPlugin({
217
217
  });
218
218
  ```
219
219
 
220
+ ### reloadOnRuntimeErrors
221
+
222
+ - Type: `boolean`
223
+ - Default: `false`
224
+
225
+ Config the plugin whether trigger a full page reload when an unrecoverable runtime error is encountered.
226
+
227
+ Currently, only module factory undefined error is considered as unrecoverable runtime error.
228
+
229
+ ```js
230
+ new ReactRefreshPlugin({
231
+ reloadOnRuntimeErrors: true,
232
+ });
233
+ ```
234
+
220
235
  ## Credits
221
236
 
222
237
  Thanks to the [react-refresh-webpack-plugin](https://github.com/pmmmwh/react-refresh-webpack-plugin) created by [@pmmmwh](https://github.com/pmmmwh), which inspires implement this plugin.
@@ -240,7 +240,12 @@ function render() {
240
240
  */
241
241
  function cleanup() {
242
242
  // Clean up and reset all internal state.
243
- document.body.removeChild(iframeRoot);
243
+ try {
244
+ document.body.removeChild(iframeRoot);
245
+ } catch (e) {
246
+ // In case user render react app directly to body, will trigger `NotFoundError` when recovery from an Error
247
+ // https://developer.mozilla.org/en-US/docs/Web/API/Node/removeChild#exceptions
248
+ }
244
249
  scheduledRenderFn = null;
245
250
  root = null;
246
251
  iframeRoot = null;
@@ -14,7 +14,13 @@ function refresh(moduleId, webpackHot) {
14
14
  if (typeof __react_refresh_test__ !== 'undefined') {
15
15
  testMode = __react_refresh_test__;
16
16
  }
17
- RefreshUtils.executeRuntime(exports, moduleId, webpackHot, errorOverlay, testMode);
17
+ RefreshUtils.executeRuntime(
18
+ exports,
19
+ moduleId,
20
+ webpackHot,
21
+ errorOverlay,
22
+ testMode,
23
+ );
18
24
  };
19
25
  if (typeof Promise !== 'undefined' && currentExports instanceof Promise) {
20
26
  currentExports.then(fn);
@@ -209,6 +209,7 @@ function shouldInvalidateReactRefreshBoundary(prevExports, nextExports) {
209
209
  }
210
210
 
211
211
  var enqueueUpdate = createDebounceUpdate();
212
+
212
213
  function executeRuntime(
213
214
  moduleExports,
214
215
  moduleId,
@@ -245,6 +246,15 @@ function executeRuntime(
245
246
  * @returns {void}
246
247
  */
247
248
  function hotErrorHandler(error) {
249
+ console.error(error);
250
+ if (
251
+ __reload_on_runtime_errors__ &&
252
+ isUnrecoverableRuntimeError(error)
253
+ ) {
254
+ location.reload();
255
+ return;
256
+ }
257
+
248
258
  if (typeof refreshOverlay !== 'undefined' && refreshOverlay) {
249
259
  refreshOverlay.handleRuntimeError(error);
250
260
  }
@@ -287,6 +297,10 @@ function executeRuntime(
287
297
  }
288
298
  }
289
299
 
300
+ function isUnrecoverableRuntimeError(error) {
301
+ return error.message.startsWith('RuntimeError: factory is undefined');
302
+ }
303
+
290
304
  module.exports = Object.freeze({
291
305
  enqueueUpdate: enqueueUpdate,
292
306
  executeRuntime: executeRuntime,
package/dist/index.js CHANGED
@@ -79,6 +79,7 @@ class ReactRefreshRspackPlugin {
79
79
  __react_refresh_library__: JSON.stringify(compiler.webpack.Template.toIdentifier(this.options.library ||
80
80
  compiler.options.output.uniqueName ||
81
81
  compiler.options.output.library)),
82
+ __reload_on_runtime_errors__: this.options.reloadOnRuntimeErrors,
82
83
  };
83
84
  const providedModules = {
84
85
  __react_refresh_utils__: paths_1.refreshUtilsPath,
package/dist/options.d.ts CHANGED
@@ -75,6 +75,11 @@ export type PluginOptions = {
75
75
  * @default true
76
76
  */
77
77
  injectEntry?: boolean;
78
+ /**
79
+ * Whether to reload the page on runtime errors. E.g: undefined module factory
80
+ * @default false
81
+ */
82
+ reloadOnRuntimeErrors?: boolean;
78
83
  };
79
84
  export interface NormalizedPluginOptions extends Required<PluginOptions> {
80
85
  overlay: false | OverlayOptions;
package/dist/options.js CHANGED
@@ -34,6 +34,7 @@ function normalizeOptions(options) {
34
34
  d(options, 'forceEnable', false);
35
35
  d(options, 'injectLoader', true);
36
36
  d(options, 'injectEntry', true);
37
+ d(options, 'reloadOnRuntimeErrors', false);
37
38
  options.overlay = normalizeOverlay(options.overlay);
38
39
  return options;
39
40
  }
@@ -1,4 +1,4 @@
1
- import { ReactRefreshRspackPlugin, type PluginOptions } from '../dist/index.js';
1
+ import { type PluginOptions, ReactRefreshRspackPlugin } from '../dist/index.js';
2
2
 
3
3
  export type { PluginOptions };
4
4
  export { ReactRefreshRspackPlugin };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rspack/plugin-react-refresh",
3
- "version": "1.5.0",
3
+ "version": "1.5.1",
4
4
  "repository": "https://github.com/rspack-contrib/rspack-plugin-react-refresh",
5
5
  "license": "MIT",
6
6
  "description": "React refresh plugin for Rspack",
@@ -36,6 +36,8 @@
36
36
  "@rspack/core": "1.4.11",
37
37
  "@types/jest": "29.5.14",
38
38
  "@types/node": "^22.17.0",
39
+ "bumpp": "^10.2.3",
40
+ "cac": "^6.7.14",
39
41
  "cross-env": "^10.0.0",
40
42
  "execa": "9.6.0",
41
43
  "fs-extra": "11.3.0",
@@ -73,6 +75,7 @@
73
75
  "lint": "biome check .",
74
76
  "lint:write": "biome check . --write",
75
77
  "test": "jest --colors",
76
- "release": "node ./scripts/release.mjs"
78
+ "release": "node ./scripts/release.mjs",
79
+ "bump": "npx bumpp --no-push --no-tag --no-commit"
77
80
  }
78
81
  }