Skip to content

Commit bfa2041

Browse files
committed
refactor: modernize react refresh runtime helpers
1 parent 6815c62 commit bfa2041

File tree

3 files changed

+94
-100
lines changed

3 files changed

+94
-100
lines changed

client/reactRefresh.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,17 @@ import { executeRuntime, getModuleExports } from './refreshUtils.js';
66

77
function refresh(moduleId, hot) {
88
const currentExports = getModuleExports(moduleId);
9-
const fn = (exports) => {
10-
var testMode;
11-
if (typeof __react_refresh_test__ !== 'undefined') {
12-
testMode = __react_refresh_test__;
13-
}
14-
executeRuntime(exports, moduleId, hot, testMode);
9+
const runRefresh = (moduleExports) => {
10+
const testMode =
11+
typeof __react_refresh_test__ !== 'undefined'
12+
? __react_refresh_test__
13+
: undefined;
14+
executeRuntime(moduleExports, moduleId, hot, testMode);
1515
};
1616
if (typeof Promise !== 'undefined' && currentExports instanceof Promise) {
17-
currentExports.then(fn);
17+
currentExports.then(runRefresh);
1818
} else {
19-
fn(currentExports);
19+
runRefresh(currentExports);
2020
}
2121
}
2222

client/reactRefreshEntry.js

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
11
import { injectIntoGlobalHook } from 'react-refresh/runtime';
22

3-
var safeThis = (function () {
3+
const safeThis = (() => {
44
// copied from core-js-pure/features/global-this
55
'use strict';
66

7-
var check = function (it) {
8-
return it && it.Math == Math && it;
9-
};
7+
const check = (it) => it && it.Math === Math && it;
108

119
// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
1210
// eslint-disable-next-line es/no-global-this -- safe
1311
return (
14-
check(typeof globalThis == 'object' && globalThis) ||
15-
check(typeof window == 'object' && window) ||
12+
check(typeof globalThis === 'object' && globalThis) ||
13+
check(typeof window === 'object' && window) ||
1614
// eslint-disable-next-line no-restricted-globals -- safe
17-
check(typeof self == 'object' && self) ||
18-
check(typeof __webpack_require__.g == 'object' && __webpack_require__.g) ||
15+
check(typeof self === 'object' && self) ||
16+
check(typeof __webpack_require__.g === 'object' && __webpack_require__.g) ||
1917
// eslint-disable-next-line no-new-func -- fallback
2018
(function () {
2119
return this;
@@ -27,13 +25,13 @@ var safeThis = (function () {
2725

2826
if (process.env.NODE_ENV !== 'production') {
2927
if (typeof safeThis !== 'undefined') {
30-
var $RefreshInjected$ = '__reactRefreshInjected';
28+
let $RefreshInjected$ = '__reactRefreshInjected';
3129
// Namespace the injected flag (if necessary) for monorepo compatibility
3230
if (
3331
typeof __react_refresh_library__ !== 'undefined' &&
3432
__react_refresh_library__
3533
) {
36-
$RefreshInjected$ += '_' + __react_refresh_library__;
34+
$RefreshInjected$ += `_${__react_refresh_library__}`;
3735
}
3836

3937
// Only inject the runtime if it hasn't been injected

client/refreshUtils.js

Lines changed: 78 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,22 @@ function getModuleExports(moduleId) {
2020
return {};
2121
}
2222

23-
var maybeModule = __webpack_require__.c[moduleId];
23+
const maybeModule = __webpack_require__.c[moduleId];
2424
if (typeof maybeModule === 'undefined') {
2525
// `moduleId` is available but the module in cache is unavailable,
2626
// which indicates the module is somehow corrupted (e.g. broken Webpacak `module` globals).
2727
// We will warn the user (as this is likely a mistake) and assume they cannot be refreshed.
2828
console.warn(
29-
'[React Refresh] Failed to get exports for module: ' + moduleId + '.',
29+
`[React Refresh] Failed to get exports for module: ${moduleId}.`,
3030
);
3131
return {};
3232
}
3333

34-
var exportsOrPromise = maybeModule.exports;
34+
const exportsOrPromise = maybeModule.exports;
3535
if (typeof Promise !== 'undefined' && exportsOrPromise instanceof Promise) {
36-
return exportsOrPromise.then(function (exports) {
37-
return exports;
38-
});
36+
return exportsOrPromise.then((moduleExports) => moduleExports);
3937
}
38+
4039
return exportsOrPromise;
4140
}
4241

@@ -49,15 +48,14 @@ function getModuleExports(moduleId) {
4948
* @returns {string[]} A React refresh boundary signature array.
5049
*/
5150
function getReactRefreshBoundarySignature(moduleExports) {
52-
var signature = [];
53-
signature.push(getFamilyByType(moduleExports));
51+
const signature = [getFamilyByType(moduleExports)];
5452

5553
if (moduleExports == null || typeof moduleExports !== 'object') {
5654
// Exit if we can't iterate over exports.
5755
return signature;
5856
}
5957

60-
for (var key in moduleExports) {
58+
for (const key in moduleExports) {
6159
if (key === '__esModule') {
6260
continue;
6361
}
@@ -78,24 +76,26 @@ function createDebounceUpdate() {
7876
* A cached setTimeout handler.
7977
* @type {number | undefined}
8078
*/
81-
var refreshTimeout;
79+
let refreshTimeout;
8280

8381
/**
8482
* Performs react refresh on a delay.
8583
* @param {function(): void} [callback]
8684
* @returns {void}
8785
*/
88-
function enqueueUpdate(callback) {
89-
if (typeof refreshTimeout === 'undefined') {
90-
refreshTimeout = setTimeout(function () {
91-
refreshTimeout = undefined;
92-
performReactRefresh();
93-
if (callback) {
94-
callback();
95-
}
96-
}, 30);
86+
const enqueueUpdate = (callback) => {
87+
if (typeof refreshTimeout !== 'undefined') {
88+
return;
9789
}
98-
}
90+
91+
refreshTimeout = setTimeout(() => {
92+
refreshTimeout = undefined;
93+
performReactRefresh();
94+
if (callback) {
95+
callback();
96+
}
97+
}, 30);
98+
};
9999

100100
return enqueueUpdate;
101101
}
@@ -120,9 +120,9 @@ function isReactRefreshBoundary(moduleExports) {
120120
return false;
121121
}
122122

123-
var hasExports = false;
124-
var areAllExportsComponents = true;
125-
for (var key in moduleExports) {
123+
let hasExports = false;
124+
let areAllExportsComponents = true;
125+
for (const key in moduleExports) {
126126
hasExports = true;
127127

128128
// This is the ES Module indicator flag
@@ -134,7 +134,7 @@ function isReactRefreshBoundary(moduleExports) {
134134
// as Rspack/webpack manually assigns ESM exports to getters,
135135
// without any side-effects attached.
136136
// Ref: https://github.com/webpack/webpack/blob/b93048643fe74de2a6931755911da1212df55897/lib/MainTemplate.js#L281
137-
var exportValue = moduleExports[key];
137+
const exportValue = moduleExports[key];
138138
if (!isLikelyComponentType(exportValue)) {
139139
areAllExportsComponents = false;
140140
}
@@ -154,7 +154,7 @@ function isReactRefreshBoundary(moduleExports) {
154154
function registerExportsForReactRefresh(moduleExports, moduleId) {
155155
if (isLikelyComponentType(moduleExports)) {
156156
// Register module.exports if it is likely a component
157-
register(moduleExports, moduleId + ' %exports%');
157+
register(moduleExports, `${moduleId} %exports%`);
158158
}
159159

160160
if (
@@ -166,15 +166,15 @@ function registerExportsForReactRefresh(moduleExports, moduleId) {
166166
return;
167167
}
168168

169-
for (var key in moduleExports) {
169+
for (const key in moduleExports) {
170170
// Skip registering the ES Module indicator
171171
if (key === '__esModule') {
172172
continue;
173173
}
174174

175-
var exportValue = moduleExports[key];
175+
const exportValue = moduleExports[key];
176176
if (isLikelyComponentType(exportValue)) {
177-
var typeID = moduleId + ' %exports% ' + key;
177+
const typeID = `${moduleId} %exports% ${key}`;
178178
register(exportValue, typeID);
179179
}
180180
}
@@ -189,72 +189,68 @@ function registerExportsForReactRefresh(moduleExports, moduleId) {
189189
* @returns {boolean} Whether the React refresh boundary should be invalidated.
190190
*/
191191
function shouldInvalidateReactRefreshBoundary(prevExports, nextExports) {
192-
var prevSignature = getReactRefreshBoundarySignature(prevExports);
193-
var nextSignature = getReactRefreshBoundarySignature(nextExports);
194-
195-
if (prevSignature.length !== nextSignature.length) {
196-
return true;
197-
}
198-
199-
for (var i = 0; i < nextSignature.length; i += 1) {
200-
if (prevSignature[i] !== nextSignature[i]) {
201-
return true;
202-
}
203-
}
204-
205-
return false;
192+
const prevSignature = getReactRefreshBoundarySignature(prevExports);
193+
const nextSignature = getReactRefreshBoundarySignature(nextExports);
194+
195+
return (
196+
prevSignature.length !== nextSignature.length ||
197+
nextSignature.some(
198+
(signatureItem, index) => prevSignature[index] !== signatureItem,
199+
)
200+
);
206201
}
207202

208-
var enqueueUpdate = createDebounceUpdate();
203+
const enqueueUpdate = createDebounceUpdate();
209204

210205
function executeRuntime(moduleExports, moduleId, hot, isTest) {
211206
registerExportsForReactRefresh(moduleExports, moduleId);
212207

213208
if (hot) {
214-
var isHotUpdate = !!hot.data;
215-
var prevExports;
209+
const isHotUpdate = Boolean(hot.data);
210+
let prevExports;
216211
if (isHotUpdate) {
217212
prevExports = hot.data.prevExports;
218213
}
219214

220215
if (isReactRefreshBoundary(moduleExports)) {
221-
hot.dispose(
222-
/**
223-
* A callback to performs a full refresh if React has unrecoverable errors,
224-
* and also caches the to-be-disposed module.
225-
* @param {*} data A hot module data object from Rspack HMR.
226-
* @returns {void}
227-
*/
228-
function hotDisposeCallback(data) {
229-
// We have to mutate the data object to get data registered and cached
230-
data.prevExports = moduleExports;
231-
},
232-
);
233-
hot.accept(
234-
/**
235-
* An error handler to allow self-recovering behaviours.
236-
* @param {Error} error An error occurred during evaluation of a module.
237-
* @returns {void}
238-
*/
239-
function hotErrorHandler(error) {
240-
console.error(error);
241-
if (
242-
__reload_on_runtime_errors__ &&
243-
isUnrecoverableRuntimeError(error)
244-
) {
245-
location.reload();
246-
return;
247-
}
248-
249-
if (typeof isTest !== 'undefined' && isTest) {
250-
if (window.onHotAcceptError) {
251-
window.onHotAcceptError(error.message);
252-
}
253-
}
254-
255-
__webpack_require__.c[moduleId].hot.accept(hotErrorHandler);
256-
},
257-
);
216+
/**
217+
* A callback to performs a full refresh if React has unrecoverable errors,
218+
* and also caches the to-be-disposed module.
219+
* @param {*} data A hot module data object from Rspack HMR.
220+
* @returns {void}
221+
*/
222+
const hotDisposeCallback = (data) => {
223+
// We have to mutate the data object to get data registered and cached
224+
data.prevExports = moduleExports;
225+
};
226+
/**
227+
* An error handler to allow self-recovering behaviors.
228+
* @param {Error} error An error occurred during evaluation of a module.
229+
* @returns {void}
230+
*/
231+
const hotErrorHandler = (error) => {
232+
console.error(error);
233+
if (
234+
__reload_on_runtime_errors__ &&
235+
isUnrecoverableRuntimeError(error)
236+
) {
237+
location.reload();
238+
return;
239+
}
240+
241+
if (
242+
typeof isTest !== 'undefined' &&
243+
isTest &&
244+
window.onHotAcceptError
245+
) {
246+
window.onHotAcceptError(error.message);
247+
}
248+
249+
__webpack_require__.c[moduleId].hot.accept(hotErrorHandler);
250+
};
251+
252+
hot.dispose(hotDisposeCallback);
253+
hot.accept(hotErrorHandler);
258254

259255
if (isHotUpdate) {
260256
if (

0 commit comments

Comments
 (0)