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.
98 lines
3.1 KiB
98 lines
3.1 KiB
/** @typedef {string | string[] | import('webpack').Entry} StaticEntry */ |
|
/** @typedef {StaticEntry | import('webpack').EntryFunc} WebpackEntry */ |
|
|
|
const EntryParseError = new Error( |
|
[ |
|
'[ReactRefreshPlugin]', |
|
'Failed to parse the Webpack `entry` object!', |
|
'Please ensure the `entry` option in your Webpack config is specified.', |
|
].join(' ') |
|
); |
|
|
|
/** |
|
* Webpack entries related to socket integrations. |
|
* They have to run before any code that sets up the error overlay. |
|
* @type {string[]} |
|
*/ |
|
const socketEntries = [ |
|
'webpack-dev-server/client', |
|
'webpack-hot-middleware/client', |
|
'webpack-plugin-serve/client', |
|
'react-dev-utils/webpackHotDevClient', |
|
]; |
|
|
|
/** |
|
* Checks if a Webpack entry string is related to socket integrations. |
|
* @param {string} entry A Webpack entry string. |
|
* @returns {boolean} Whether the entry is related to socket integrations. |
|
*/ |
|
function isSocketEntry(entry) { |
|
return socketEntries.some((socketEntry) => entry.includes(socketEntry)); |
|
} |
|
|
|
/** |
|
* Injects an entry to the bundle for react-refresh. |
|
* @param {WebpackEntry} [originalEntry] A Webpack entry object. |
|
* @param {import('./getAdditionalEntries').AdditionalEntries} additionalEntries An object that contains the Webpack entries for prepending and the overlay feature |
|
* @returns {WebpackEntry} An injected entry object. |
|
*/ |
|
function injectRefreshEntry(originalEntry, additionalEntries) { |
|
const { prependEntries, overlayEntries } = additionalEntries; |
|
|
|
// Single string entry point |
|
if (typeof originalEntry === 'string') { |
|
if (isSocketEntry(originalEntry)) { |
|
return [...prependEntries, originalEntry, ...overlayEntries]; |
|
} |
|
|
|
return [...prependEntries, ...overlayEntries, originalEntry]; |
|
} |
|
// Single array entry point |
|
if (Array.isArray(originalEntry)) { |
|
if (originalEntry.length === 0) { |
|
throw EntryParseError; |
|
} |
|
|
|
const socketEntryIndex = originalEntry.findIndex(isSocketEntry); |
|
|
|
let socketAndPrecedingEntries = []; |
|
if (socketEntryIndex !== -1) { |
|
socketAndPrecedingEntries = originalEntry.splice(0, socketEntryIndex + 1); |
|
} |
|
|
|
return [...prependEntries, ...socketAndPrecedingEntries, ...overlayEntries, ...originalEntry]; |
|
} |
|
// Multiple entry points |
|
if (typeof originalEntry === 'object') { |
|
const entries = Object.entries(originalEntry); |
|
if (entries.length === 0) { |
|
throw EntryParseError; |
|
} |
|
|
|
return entries.reduce( |
|
(acc, [curKey, curEntry]) => ({ |
|
...acc, |
|
[curKey]: |
|
typeof curEntry === 'object' && curEntry.import |
|
? { |
|
...curEntry, |
|
import: injectRefreshEntry(curEntry.import, additionalEntries), |
|
} |
|
: injectRefreshEntry(curEntry, additionalEntries), |
|
}), |
|
{} |
|
); |
|
} |
|
// Dynamic entry points |
|
if (typeof originalEntry === 'function') { |
|
return (...args) => |
|
Promise.resolve(originalEntry(...args)).then((resolvedEntry) => |
|
injectRefreshEntry(resolvedEntry, additionalEntries) |
|
); |
|
} |
|
|
|
throw EntryParseError; |
|
} |
|
|
|
module.exports = injectRefreshEntry; |
|
module.exports.socketEntries = socketEntries;
|
|
|