You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
271 lines
8.9 KiB
271 lines
8.9 KiB
/* global __webpack_require__ */ |
|
var Refresh = require('react-refresh/runtime'); |
|
|
|
/** |
|
* Extracts exports from a webpack module object. |
|
* @param {string} moduleId A Webpack module ID. |
|
* @returns {*} An exports object from the module. |
|
*/ |
|
function getModuleExports(moduleId) { |
|
if (typeof moduleId === 'undefined') { |
|
// `moduleId` is unavailable, which indicates that this module is not in the cache, |
|
// which means we won't be able to capture any exports, |
|
// and thus they cannot be refreshed safely. |
|
// These are likely runtime or dynamically generated modules. |
|
return {}; |
|
} |
|
|
|
var maybeModule = __webpack_require__.c[moduleId]; |
|
if (typeof maybeModule === 'undefined') { |
|
// `moduleId` is available but the module in cache is unavailable, |
|
// which indicates the module is somehow corrupted (e.g. broken Webpacak `module` globals). |
|
// We will warn the user (as this is likely a mistake) and assume they cannot be refreshed. |
|
console.warn('[React Refresh] Failed to get exports for module: ' + moduleId + '.'); |
|
return {}; |
|
} |
|
|
|
var exportsOrPromise = maybeModule.exports; |
|
if (typeof Promise !== 'undefined' && exportsOrPromise instanceof Promise) { |
|
return exportsOrPromise.then(function (exports) { |
|
return exports; |
|
}); |
|
} |
|
return exportsOrPromise; |
|
} |
|
|
|
/** |
|
* Calculates the signature of a React refresh boundary. |
|
* If this signature changes, it's unsafe to accept the boundary. |
|
* |
|
* This implementation is based on the one in [Metro](https://github.com/facebook/metro/blob/907d6af22ac6ebe58572be418e9253a90665ecbd/packages/metro/src/lib/polyfills/require.js#L795-L816). |
|
* @param {*} moduleExports A Webpack module exports object. |
|
* @returns {string[]} A React refresh boundary signature array. |
|
*/ |
|
function getReactRefreshBoundarySignature(moduleExports) { |
|
var signature = []; |
|
signature.push(Refresh.getFamilyByType(moduleExports)); |
|
|
|
if (moduleExports == null || typeof moduleExports !== 'object') { |
|
// Exit if we can't iterate over exports. |
|
return signature; |
|
} |
|
|
|
for (var key in moduleExports) { |
|
if (key === '__esModule') { |
|
continue; |
|
} |
|
|
|
signature.push(key); |
|
signature.push(Refresh.getFamilyByType(moduleExports[key])); |
|
} |
|
|
|
return signature; |
|
} |
|
|
|
/** |
|
* Creates a helper that performs a delayed React refresh. |
|
* @returns {function(function(): void): void} A debounced React refresh function. |
|
*/ |
|
function createDebounceUpdate() { |
|
/** |
|
* A cached setTimeout handler. |
|
* @type {number | undefined} |
|
*/ |
|
var refreshTimeout; |
|
|
|
/** |
|
* Performs react refresh on a delay and clears the error overlay. |
|
* @param {function(): void} callback |
|
* @returns {void} |
|
*/ |
|
function enqueueUpdate(callback) { |
|
if (typeof refreshTimeout === 'undefined') { |
|
refreshTimeout = setTimeout(function () { |
|
refreshTimeout = undefined; |
|
Refresh.performReactRefresh(); |
|
callback(); |
|
}, 30); |
|
} |
|
} |
|
|
|
return enqueueUpdate; |
|
} |
|
|
|
/** |
|
* Checks if all exports are likely a React component. |
|
* |
|
* This implementation is based on the one in [Metro](https://github.com/facebook/metro/blob/febdba2383113c88296c61e28e4ef6a7f4939fda/packages/metro/src/lib/polyfills/require.js#L748-L774). |
|
* @param {*} moduleExports A Webpack module exports object. |
|
* @returns {boolean} Whether the exports are React component like. |
|
*/ |
|
function isReactRefreshBoundary(moduleExports) { |
|
if (Refresh.isLikelyComponentType(moduleExports)) { |
|
return true; |
|
} |
|
if (moduleExports === undefined || moduleExports === null || typeof moduleExports !== 'object') { |
|
// Exit if we can't iterate over exports. |
|
return false; |
|
} |
|
|
|
var hasExports = false; |
|
var areAllExportsComponents = true; |
|
for (var key in moduleExports) { |
|
hasExports = true; |
|
|
|
// This is the ES Module indicator flag |
|
if (key === '__esModule') { |
|
continue; |
|
} |
|
|
|
// We can (and have to) safely execute getters here, |
|
// as Webpack manually assigns harmony exports to getters, |
|
// without any side-effects attached. |
|
// Ref: https://github.com/webpack/webpack/blob/b93048643fe74de2a6931755911da1212df55897/lib/MainTemplate.js#L281 |
|
var exportValue = moduleExports[key]; |
|
if (!Refresh.isLikelyComponentType(exportValue)) { |
|
areAllExportsComponents = false; |
|
} |
|
} |
|
|
|
return hasExports && areAllExportsComponents; |
|
} |
|
|
|
/** |
|
* Checks if exports are likely a React component and registers them. |
|
* |
|
* This implementation is based on the one in [Metro](https://github.com/facebook/metro/blob/febdba2383113c88296c61e28e4ef6a7f4939fda/packages/metro/src/lib/polyfills/require.js#L818-L835). |
|
* @param {*} moduleExports A Webpack module exports object. |
|
* @param {string} moduleId A Webpack module ID. |
|
* @returns {void} |
|
*/ |
|
function registerExportsForReactRefresh(moduleExports, moduleId) { |
|
if (Refresh.isLikelyComponentType(moduleExports)) { |
|
// Register module.exports if it is likely a component |
|
Refresh.register(moduleExports, moduleId + ' %exports%'); |
|
} |
|
|
|
if (moduleExports === undefined || moduleExports === null || typeof moduleExports !== 'object') { |
|
// Exit if we can't iterate over the exports. |
|
return; |
|
} |
|
|
|
for (var key in moduleExports) { |
|
// Skip registering the ES Module indicator |
|
if (key === '__esModule') { |
|
continue; |
|
} |
|
|
|
var exportValue = moduleExports[key]; |
|
if (Refresh.isLikelyComponentType(exportValue)) { |
|
var typeID = moduleId + ' %exports% ' + key; |
|
Refresh.register(exportValue, typeID); |
|
} |
|
} |
|
} |
|
|
|
/** |
|
* Compares previous and next module objects to check for mutated boundaries. |
|
* |
|
* This implementation is based on the one in [Metro](https://github.com/facebook/metro/blob/907d6af22ac6ebe58572be418e9253a90665ecbd/packages/metro/src/lib/polyfills/require.js#L776-L792). |
|
* @param {*} prevExports The current Webpack module exports object. |
|
* @param {*} nextExports The next Webpack module exports object. |
|
* @returns {boolean} Whether the React refresh boundary should be invalidated. |
|
*/ |
|
function shouldInvalidateReactRefreshBoundary(prevExports, nextExports) { |
|
var prevSignature = getReactRefreshBoundarySignature(prevExports); |
|
var nextSignature = getReactRefreshBoundarySignature(nextExports); |
|
|
|
if (prevSignature.length !== nextSignature.length) { |
|
return true; |
|
} |
|
|
|
for (var i = 0; i < nextSignature.length; i += 1) { |
|
if (prevSignature[i] !== nextSignature[i]) { |
|
return true; |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
var enqueueUpdate = createDebounceUpdate(); |
|
function executeRuntime(moduleExports, moduleId, webpackHot, refreshOverlay, isTest) { |
|
registerExportsForReactRefresh(moduleExports, moduleId); |
|
|
|
if (webpackHot) { |
|
var isHotUpdate = !!webpackHot.data; |
|
var prevExports; |
|
if (isHotUpdate) { |
|
prevExports = webpackHot.data.prevExports; |
|
} |
|
|
|
if (isReactRefreshBoundary(moduleExports)) { |
|
webpackHot.dispose( |
|
/** |
|
* A callback to performs a full refresh if React has unrecoverable errors, |
|
* and also caches the to-be-disposed module. |
|
* @param {*} data A hot module data object from Webpack HMR. |
|
* @returns {void} |
|
*/ |
|
function hotDisposeCallback(data) { |
|
// We have to mutate the data object to get data registered and cached |
|
data.prevExports = moduleExports; |
|
} |
|
); |
|
webpackHot.accept( |
|
/** |
|
* An error handler to allow self-recovering behaviours. |
|
* @param {Error} error An error occurred during evaluation of a module. |
|
* @returns {void} |
|
*/ |
|
function hotErrorHandler(error) { |
|
if (typeof refreshOverlay !== 'undefined' && refreshOverlay) { |
|
refreshOverlay.handleRuntimeError(error); |
|
} |
|
|
|
if (typeof isTest !== 'undefined' && isTest) { |
|
if (window.onHotAcceptError) { |
|
window.onHotAcceptError(error.message); |
|
} |
|
} |
|
|
|
__webpack_require__.c[moduleId].hot.accept(hotErrorHandler); |
|
} |
|
); |
|
|
|
if (isHotUpdate) { |
|
if ( |
|
isReactRefreshBoundary(prevExports) && |
|
shouldInvalidateReactRefreshBoundary(prevExports, moduleExports) |
|
) { |
|
webpackHot.invalidate(); |
|
} else { |
|
enqueueUpdate( |
|
/** |
|
* A function to dismiss the error overlay after performing React refresh. |
|
* @returns {void} |
|
*/ |
|
function updateCallback() { |
|
if (typeof refreshOverlay !== 'undefined' && refreshOverlay) { |
|
refreshOverlay.clearRuntimeErrors(); |
|
} |
|
} |
|
); |
|
} |
|
} |
|
} else { |
|
if (isHotUpdate && typeof prevExports !== 'undefined') { |
|
webpackHot.invalidate(); |
|
} |
|
} |
|
} |
|
} |
|
|
|
module.exports = Object.freeze({ |
|
enqueueUpdate: enqueueUpdate, |
|
executeRuntime: executeRuntime, |
|
getModuleExports: getModuleExports, |
|
isReactRefreshBoundary: isReactRefreshBoundary, |
|
shouldInvalidateReactRefreshBoundary: shouldInvalidateReactRefreshBoundary, |
|
registerExportsForReactRefresh: registerExportsForReactRefresh, |
|
});
|
|
|