/
githubmirror
/
webpack
Обзор
Документация
Войти
/
githubmirror
/
webpack
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
lib/hmr/HotModuleReplacement.runtime.js
583 строки
17 KB
Alexander Akait
feat(esm): widen analyzable output to HMR, hashed and function chunk filenames (#21653)
10 авг 2026, 09:28
Не верифицирован
10 авг 2026, 09:28
e3f177c
Код
Авторство
О чём код?
/* MIT License http://www.opensource.org/licenses/mit-license.php Author Tobias Koppers @sokra */ "use strict"; /** @typedef {string | number} ModuleId */ /** @typedef {Record<string, unknown>} HotData */ /** @typedef {(data: HotData) => void} DisposeHandler */ /** @typedef {(outdatedDependencies: ModuleId[]) => void} AcceptCallback */ /** @typedef {(err: Error, context: { moduleId: ModuleId, dependencyId?: ModuleId, module?: HotModule }) => void} AcceptErrorHandler */ /** @typedef {(status: string) => (Promise<void> | void)} StatusHandler */ /** @typedef {Record<string, unknown>} ApplyOptions */ /** @typedef {(reportError: (err: Error) => void) => Promise<ModuleId[]>} ApplyFn */ /** @typedef {(chunkId: ModuleId, fetchPriority?: string) => Promise<unknown>} EnsureChunk */ /** @typedef {(chunkId: ModuleId, importFn: () => Promise<unknown>) => Promise<unknown>} AnalyzableChunkImport */ /** @typedef {{ (id: ModuleId): unknown, e?: EnsureChunk, ei?: AnalyzableChunkImport, [name: string]: unknown }} WebpackRequire */ /** * @typedef {object} ApplyResult * @property {Error=} error fatal error that aborts the update * @property {(() => void)=} dispose dispose phase of the update * @property {ApplyFn=} apply apply phase of the update */ /** @typedef {(options: ApplyOptions) => ApplyResult} ApplyHandler */ /** @typedef {(moduleId: ModuleId, applyHandlers: ApplyHandler[]) => void} InvalidateModuleHandler */ /** @typedef {(chunkIds: ModuleId[], removedChunks: ModuleId[], removedModules: ModuleId[], promises: Promise<unknown>[], applyHandlers: ApplyHandler[], updatedModulesList: ModuleId[], css: ModuleId[] | undefined, forceLoadChunks: ModuleId[] | undefined) => void} DownloadUpdateHandler */ /** * @typedef {object} HMRManifest * @property {ModuleId[]} c updated chunk ids * @property {ModuleId[]} r removed chunk ids * @property {ModuleId[]} m removed module ids * @property {ModuleId[]=} css updated css chunk ids * @property {ModuleId[]=} f chunk ids to force-load */ /** * @typedef {object} HotModule * @property {ModuleId} id module id * @property {Hot} hot hot API of the module * @property {ModuleId[]} parents ids of modules requiring this module * @property {ModuleId[]} children ids of modules required by this module */ /** * @typedef {object} Hot * @property {Record<ModuleId, AcceptCallback>} _acceptedDependencies accept callbacks by dependency id * @property {Record<ModuleId, AcceptErrorHandler | undefined>} _acceptedErrorHandlers error handlers by dependency id * @property {Record<ModuleId, boolean>} _declinedDependencies declined dependency ids * @property {boolean | EXPECTED_FUNCTION} _selfAccepted true or the self-accept error handler * @property {boolean} _selfDeclined module declined itself * @property {boolean} _selfInvalidated module invalidated itself * @property {DisposeHandler[]} _disposeHandlers registered dispose handlers * @property {boolean} _main module is the entry of the update * @property {() => void} _requireSelf re-require the module on apply * @property {boolean} active module is not disposed * @property {(dep?: ModuleId | ModuleId[] | AcceptCallback, callback?: AcceptCallback, errorHandler?: AcceptErrorHandler) => void} accept accept updates * @property {(dep?: ModuleId | ModuleId[]) => void} decline decline updates * @property {(callback: DisposeHandler) => void} dispose add a dispose handler * @property {(callback: DisposeHandler) => void} addDisposeHandler add a dispose handler * @property {(callback: DisposeHandler) => void} removeDisposeHandler remove a dispose handler * @property {() => void} invalidate invalidate the module * @property {(applyOnUpdate?: boolean | ApplyOptions) => Promise<ModuleId[] | null>} check check for an update * @property {(options?: ApplyOptions) => Promise<ModuleId[]>} apply apply a checked update * @property {(l?: StatusHandler) => string | void} status get status or add a status handler * @property {(l: StatusHandler) => void} addStatusHandler add a status handler * @property {(l: StatusHandler) => void} removeStatusHandler remove a status handler * @property {HotData} data data left from the previous dispose */ /** @typedef {{ module: HotModule, require: WebpackRequire, id: ModuleId }} InterceptOptions */ // Globals injected by code generation; declared here only to type the template. /* eslint-disable no-unassigned-vars */ /** @type {((options: InterceptOptions) => void)[]} */ var $interceptModuleExecution$; /** @type {Record<ModuleId, HotModule>} */ var $moduleCache$; /** @type {Record<ModuleId, HotData>} */ var $hmrModuleData$; /** @type {() => Promise<HMRManifest | void>} */ var $hmrDownloadManifest$; /** @type {Record<string, DownloadUpdateHandler>} */ var $hmrDownloadUpdateHandlers$; /** @type {Record<string, InvalidateModuleHandler>} */ var $hmrInvalidateModuleHandlers$; /** @type {(id: ModuleId) => unknown} */ var __webpack_require__; /* eslint-enable no-unassigned-vars */ module.exports = function () { /** @type {Record<ModuleId, HotData>} */ var currentModuleData = {}; var installedModules = $moduleCache$; // module and require creation /** @type {ModuleId | undefined} */ var currentChildModule; /** @type {ModuleId[]} */ var currentParents = []; // status /** @type {StatusHandler[]} */ var registeredStatusHandlers = []; var currentStatus = "idle"; // while downloading var blockingPromises = 0; /** @type {(() => void)[]} */ var blockingPromisesWaiting = []; // The update info /** @type {ApplyHandler[] | undefined} */ var currentUpdateApplyHandlers; /** @type {ModuleId[] | undefined} */ var queuedInvalidatedModules; $hmrModuleData$ = currentModuleData; $interceptModuleExecution$.push(function (options) { var module = options.module; var require = createRequire(options.require, options.id); module.hot = createModuleHotObject(options.id, module); module.parents = currentParents; module.children = []; currentParents = []; options.require = require; }); $hmrDownloadUpdateHandlers$ = {}; $hmrInvalidateModuleHandlers$ = {}; /** * @param {WebpackRequire} require the original require function * @param {ModuleId} moduleId module id * @returns {WebpackRequire} hot-aware require function */ function createRequire(require, moduleId) { var me = installedModules[moduleId]; if (!me) return require; /** * @param {ModuleId} request requested module id * @returns {unknown} module exports */ var fn = function (request) { if (me.hot.active) { if (installedModules[request]) { var parents = installedModules[request].parents; if (parents.indexOf(moduleId) === -1) { parents.push(moduleId); } } else { currentParents = [moduleId]; currentChildModule = request; } if (me.children.indexOf(request) === -1) { me.children.push(request); } } else { console.warn( "[HMR] unexpected require(" + request + ") from disposed module " + moduleId ); currentParents = []; } return require(request); }; /** * @param {string} name property name * @returns {PropertyDescriptor} descriptor forwarding to require */ var createPropertyDescriptor = function (name) { return { configurable: true, enumerable: true, get: function () { return require[name]; }, set: function (value) { require[name] = value; } }; }; for (var name in require) { if ( Object.prototype.hasOwnProperty.call(require, name) && name !== "e" && name !== "ei" ) { Object.defineProperty(fn, name, createPropertyDescriptor(name)); } } // A chunk load blocks the update until it settles, and `.ei` is the analyzable // half of `.e`. A runtime that loads no chunks has neither to wrap. if (require.e) { /** @type {WebpackRequire} */ (fn).e = function (chunkId, fetchPriority) { return trackBlockingPromise( /** @type {EnsureChunk} */ (require.e)(chunkId, fetchPriority) ); }; } if (require.ei) { /** @type {WebpackRequire} */ (fn).ei = function (chunkId, importFn) { return trackBlockingPromise( /** @type {AnalyzableChunkImport} */ (require.ei)(chunkId, importFn) ); }; } return /** @type {WebpackRequire} */ (fn); } /** * @param {ModuleId} moduleId module id * @param {HotModule} me the module * @returns {Hot} hot API */ function createModuleHotObject(moduleId, me) { var _main = currentChildModule !== moduleId; /** @type {Hot} */ var hot = { // private stuff _acceptedDependencies: {}, _acceptedErrorHandlers: {}, _declinedDependencies: {}, _selfAccepted: false, _selfDeclined: false, _selfInvalidated: false, _disposeHandlers: [], _main: _main, _requireSelf: function () { currentParents = me.parents.slice(); currentChildModule = _main ? undefined : moduleId; __webpack_require__(moduleId); }, // Module API active: true, accept: function (dep, callback, errorHandler) { if (dep === undefined) hot._selfAccepted = true; else if (typeof dep === "function") hot._selfAccepted = dep; else if (typeof dep === "object" && dep !== null) { for (var i = 0; i < dep.length; i++) { hot._acceptedDependencies[dep[i]] = callback || function () {}; hot._acceptedErrorHandlers[dep[i]] = errorHandler; } } else { hot._acceptedDependencies[dep] = callback || function () {}; hot._acceptedErrorHandlers[dep] = errorHandler; } }, decline: function (dep) { if (dep === undefined) hot._selfDeclined = true; else if (typeof dep === "object" && dep !== null) for (var i = 0; i < dep.length; i++) hot._declinedDependencies[dep[i]] = true; else hot._declinedDependencies[dep] = true; }, dispose: function (callback) { hot._disposeHandlers.push(callback); }, addDisposeHandler: function (callback) { hot._disposeHandlers.push(callback); }, removeDisposeHandler: function (callback) { var idx = hot._disposeHandlers.indexOf(callback); if (idx >= 0) hot._disposeHandlers.splice(idx, 1); }, invalidate: function () { this._selfInvalidated = true; switch (currentStatus) { case "idle": currentUpdateApplyHandlers = []; Object.keys($hmrInvalidateModuleHandlers$).forEach(function (key) { $hmrInvalidateModuleHandlers$[key]( moduleId, /** @type {ApplyHandler[]} */ (currentUpdateApplyHandlers) ); }); setStatus("ready"); break; case "ready": Object.keys($hmrInvalidateModuleHandlers$).forEach(function (key) { $hmrInvalidateModuleHandlers$[key]( moduleId, /** @type {ApplyHandler[]} */ (currentUpdateApplyHandlers) ); }); break; case "prepare": case "check": case "dispose": case "apply": (queuedInvalidatedModules = queuedInvalidatedModules || []).push( moduleId ); break; default: // ignore requests in error states break; } }, // Management API check: hotCheck, apply: hotApply, status: function (l) { if (!l) return currentStatus; registeredStatusHandlers.push(l); }, addStatusHandler: function (l) { registeredStatusHandlers.push(l); }, removeStatusHandler: function (l) { var idx = registeredStatusHandlers.indexOf(l); if (idx >= 0) registeredStatusHandlers.splice(idx, 1); }, // inherit from previous dispose call data: currentModuleData[moduleId] }; currentChildModule = undefined; return hot; } /** * @param {string} newStatus new status * @returns {Promise<void>} promise resolving when all handlers ran */ function setStatus(newStatus) { currentStatus = newStatus; /** @type {(Promise<void> | void)[]} */ var results = []; for (var i = 0; i < registeredStatusHandlers.length; i++) results[i] = registeredStatusHandlers[i].call(null, newStatus); return Promise.all(results).then(function () {}); } function unblock() { if (--blockingPromises === 0) { setStatus("ready").then(function () { if (blockingPromises === 0) { var list = blockingPromisesWaiting; blockingPromisesWaiting = []; for (var i = 0; i < list.length; i++) { list[i](); } } }); } } /** * @param {Promise<unknown>} promise blocking promise * @returns {Promise<unknown>} the same promise */ function trackBlockingPromise(promise) { switch (currentStatus) { case "ready": setStatus("prepare"); /* fallthrough */ case "prepare": blockingPromises++; promise.then(unblock, unblock); return promise; default: return promise; } } /** * @param {() => Promise<ModuleId[]>} fn function to run once unblocked * @returns {Promise<ModuleId[]>} result of fn */ function waitForBlockingPromises(fn) { if (blockingPromises === 0) return fn(); return /** @type {Promise<ModuleId[]>} */ ( new Promise(function (resolve) { blockingPromisesWaiting.push(function () { resolve(fn()); }); }) ); } /** * @param {boolean | ApplyOptions=} applyOnUpdate apply the update right away * @returns {Promise<ModuleId[] | null>} updated module ids or null */ function hotCheck(applyOnUpdate) { if (currentStatus !== "idle") { throw new Error("check() is only allowed in idle status"); } return setStatus("check") .then($hmrDownloadManifest$) .then(function (update) { if (!update) { return setStatus(applyInvalidatedModules() ? "ready" : "idle").then( function () { return null; } ); } return setStatus("prepare").then(function () { /** @type {ModuleId[]} */ var updatedModules = []; currentUpdateApplyHandlers = []; return Promise.all( Object.keys($hmrDownloadUpdateHandlers$).reduce(function ( promises, key ) { $hmrDownloadUpdateHandlers$[key]( update.c, update.r, update.m, promises, /** @type {ApplyHandler[]} */ (currentUpdateApplyHandlers), updatedModules, update.css, update.f ); return promises; }, /** @type {Promise<unknown>[]} */ ([])) ).then(function () { return waitForBlockingPromises(function () { if (applyOnUpdate) { return internalApply(applyOnUpdate); } return setStatus("ready").then(function () { return updatedModules; }); }); }); }); }); } /** * @param {ApplyOptions=} options apply options * @returns {Promise<ModuleId[]>} updated module ids */ function hotApply(options) { if (currentStatus !== "ready") { return Promise.resolve().then(function () { throw new Error( "apply() is only allowed in ready status (state: " + currentStatus + ")" ); }); } return internalApply(options); } /** * @param {boolean | ApplyOptions=} options apply options * @returns {Promise<ModuleId[]>} updated module ids */ function internalApply(options) { options = options || {}; applyInvalidatedModules(); var results = /** @type {ApplyHandler[]} */ ( currentUpdateApplyHandlers ).map(function (handler) { return handler(/** @type {ApplyOptions} */ (options)); }); currentUpdateApplyHandlers = undefined; var errors = results .map(function (r) { return r.error; }) .filter(Boolean); if (errors.length > 0) { return setStatus("abort").then(function () { throw errors[0]; }); } // Now in "dispose" phase var disposePromise = setStatus("dispose"); results.forEach(function (result) { if (result.dispose) result.dispose(); }); // Now in "apply" phase var applyPromise = setStatus("apply"); /** @type {Error | undefined} */ var error; /** * @param {Error} err error thrown while applying * @returns {void} */ var reportError = function (err) { if (!error) error = err; }; /** @type {ModuleId[]} */ var outdatedModules = []; /** * @returns {Promise<ModuleId[]>} updated module ids */ var onAccepted = function () { return Promise.all([disposePromise, applyPromise]).then(function () { // handle errors in accept handlers and self accepted module load if (error) { return setStatus("fail").then(function () { throw error; }); } if (queuedInvalidatedModules) { return internalApply(options).then(function (list) { outdatedModules.forEach(function (moduleId) { if (list.indexOf(moduleId) < 0) list.push(moduleId); }); return list; }); } return setStatus("idle").then(function () { return outdatedModules; }); }); }; return Promise.all( results .filter(function (result) { return result.apply; }) .map(function (result) { return /** @type {ApplyFn} */ (result.apply)(reportError); }) ) .then(function (applyResults) { applyResults.forEach(function (modules) { if (modules) { for (var i = 0; i < modules.length; i++) { outdatedModules.push(modules[i]); } } }); }) .then(onAccepted); } /** * @returns {boolean | undefined} true when invalidated modules were applied */ function applyInvalidatedModules() { if (queuedInvalidatedModules) { if (!currentUpdateApplyHandlers) currentUpdateApplyHandlers = []; Object.keys($hmrInvalidateModuleHandlers$).forEach(function (key) { /** @type {ModuleId[]} */ (queuedInvalidatedModules).forEach( function (moduleId) { $hmrInvalidateModuleHandlers$[key]( moduleId, /** @type {ApplyHandler[]} */ (currentUpdateApplyHandlers) ); } ); }); queuedInvalidatedModules = undefined; return true; } } };