/
githubmirror
/
webpack
Обзор
Документация
Войти
/
githubmirror
/
webpack
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
v5.109.2
lib/esm/ModuleChunkLoadingRuntimeModule.js
454 строки
16 KB
Sebastian Beltran
feat: annotate schema options with added keywords (#21473)
28 июл 2026, 18:27
Не верифицирован
28 июл 2026, 18:27
774e7e4
Код
Авторство
О чём код?
/* MIT License http://www.opensource.org/licenses/mit-license.php */ "use strict"; const { SyncWaterfallHook } = require("tapable"); /** @typedef {import("../Compilation")} Compilation */ const RuntimeGlobals = require("../RuntimeGlobals"); const RuntimeModule = require("../RuntimeModule"); const Template = require("../Template"); const { generateJavascriptHMR } = require("../hmr/JavascriptHotModuleReplacementHelper"); const { chunkHasJs, getChunkFilenameTemplate } = require("../javascript/JavascriptModulesPlugin"); const { getInitialChunkIds } = require("../javascript/StartupHelpers"); const compileBooleanMatcher = require("../util/compileBooleanMatcher"); const createHooksRegistry = require("../util/createHooksRegistry"); const { getUndoPath } = require("../util/identifier"); /** @typedef {import("../Chunk")} Chunk */ /** @typedef {import("../ChunkGraph")} ChunkGraph */ /** @typedef {import("../Module").ReadOnlyRuntimeRequirements} ReadOnlyRuntimeRequirements */ const createCompilationHooks = () => ({ /** * @type {SyncWaterfallHook<[string, Chunk]>} * @since 5.41.0 */ linkPreload: new SyncWaterfallHook(["source", "chunk"]), /** * @type {SyncWaterfallHook<[string, Chunk]>} * @since 5.41.0 */ linkPrefetch: new SyncWaterfallHook(["source", "chunk"]) }); /** * @typedef {ReturnType<typeof createCompilationHooks>} JsonpCompilationPluginHooks */ class ModuleChunkLoadingRuntimeModule extends RuntimeModule { /** * Creates an instance of ModuleChunkLoadingRuntimeModule. * @param {ReadOnlyRuntimeRequirements} runtimeRequirements runtime requirements */ constructor(runtimeRequirements) { super("import chunk loading", RuntimeModule.STAGE_ATTACH); /** @type {ReadOnlyRuntimeRequirements} */ this._runtimeRequirements = runtimeRequirements; } /** * Returns generated code. * @private * @param {Chunk} chunk chunk * @param {string} rootOutputDir root output directory * @returns {string} generated code */ _generateBaseUri(chunk, rootOutputDir) { const options = chunk.getEntryOptions(); if (options && options.baseUri) { return `${RuntimeGlobals.baseURI} = ${JSON.stringify(options.baseUri)};`; } const compilation = /** @type {Compilation} */ (this.compilation); const { outputOptions: { importMetaName } } = compilation; return `${RuntimeGlobals.baseURI} = new URL(${JSON.stringify( rootOutputDir )}, ${importMetaName}.url);`; } /** * Generates runtime code for this runtime module. * @returns {string | null} runtime code */ generate() { const compilation = /** @type {Compilation} */ (this.compilation); const chunkGraph = /** @type {ChunkGraph} */ (this.chunkGraph); const chunk = /** @type {Chunk} */ (this.chunk); const environment = compilation.outputOptions.environment; const { runtimeTemplate, outputOptions: { importFunctionName, crossOriginLoading, charset } } = compilation; const fn = RuntimeGlobals.ensureChunkHandlers; const withBaseURI = this._runtimeRequirements.has(RuntimeGlobals.baseURI); const withExternalInstallChunk = this._runtimeRequirements.has( RuntimeGlobals.externalInstallChunk ); const withAnalyzableImport = this._runtimeRequirements.has( RuntimeGlobals.analyzableChunkImport ); const withLoading = this._runtimeRequirements.has( RuntimeGlobals.ensureChunkHandlers ); const withOnChunkLoad = this._runtimeRequirements.has( RuntimeGlobals.onChunksLoaded ); const withHmr = this._runtimeRequirements.has( RuntimeGlobals.hmrDownloadUpdateHandlers ); const withHmrManifest = this._runtimeRequirements.has( RuntimeGlobals.hmrDownloadManifest ); const { linkPreload, linkPrefetch } = ModuleChunkLoadingRuntimeModule.getCompilationHooks(compilation); const isNeutralPlatform = runtimeTemplate.isNeutralPlatform(); const withPrefetch = (environment.document || isNeutralPlatform) && this._runtimeRequirements.has(RuntimeGlobals.prefetchChunkHandlers) && chunk.hasChildByOrder(chunkGraph, "prefetch", true, chunkHasJs); const withPreload = (environment.document || isNeutralPlatform) && this._runtimeRequirements.has(RuntimeGlobals.preloadChunkHandlers) && chunk.hasChildByOrder(chunkGraph, "preload", true, chunkHasJs); const conditionMap = chunkGraph.getChunkConditionMap(chunk, chunkHasJs); const hasJsMatcher = compileBooleanMatcher(conditionMap); const initialChunkIds = getInitialChunkIds(chunk, chunkGraph, chunkHasJs); const outputName = compilation.getPath( getChunkFilenameTemplate(chunk, compilation.outputOptions), { chunk, contentHashType: "javascript" } ); const rootOutputDir = getUndoPath( outputName, compilation.outputOptions.path, true ); const stateExpression = withHmr ? `${RuntimeGlobals.hmrRuntimeStatePrefix}_module` : undefined; const cst = runtimeTemplate.renderConst(); const lt = runtimeTemplate.renderLet(); const installedChunksObject = `{\n${Template.indent( Array.from(initialChunkIds, (id) => `${JSON.stringify(id)}: 0`).join( ",\n" ) )}\n}`; return Template.asString([ withBaseURI ? this._generateBaseUri(chunk, rootOutputDir) : "// no baseURI", "", "// object to store loaded and loading chunks", "// undefined = chunk not loaded, null = chunk preloaded/prefetched", "// [resolve, Promise] = chunk loading, 0 = chunk loaded", `${cst} installedChunks = ${ stateExpression ? runtimeTemplate.assignOr(stateExpression, installedChunksObject) : installedChunksObject };`, "", withLoading || withExternalInstallChunk || withAnalyzableImport ? `${cst} installChunk = ${runtimeTemplate.basicFunction("data", [ runtimeTemplate.destructureObject( [ RuntimeGlobals.esmIds, RuntimeGlobals.esmModules, RuntimeGlobals.esmRuntime ], "data" ), '// add "modules" to the modules object,', '// then flag all "ids" as loaded and fire callback', "var moduleId, chunkId, i = 0;", `for(moduleId in ${RuntimeGlobals.esmModules}) {`, Template.indent([ `if(${RuntimeGlobals.hasOwnProperty}(${RuntimeGlobals.esmModules}, moduleId)) {`, Template.indent( `${RuntimeGlobals.moduleFactories}[moduleId] = ${RuntimeGlobals.esmModules}[moduleId];` ), "}" ]), "}", `if(${RuntimeGlobals.esmRuntime}) ${RuntimeGlobals.esmRuntime}(${RuntimeGlobals.require});`, `for(;i < ${RuntimeGlobals.esmIds}.length; i++) {`, Template.indent([ `chunkId = ${RuntimeGlobals.esmIds}[i];`, `if(${RuntimeGlobals.hasOwnProperty}(installedChunks, chunkId) && installedChunks[chunkId]) {`, Template.indent("installedChunks[chunkId][0]();"), "}", `installedChunks[${RuntimeGlobals.esmIds}[i]] = 0;` ]), "}", withOnChunkLoad ? `${RuntimeGlobals.onChunksLoaded}();` : "" ])}` : "// no install chunk", "", withLoading ? Template.asString([ `${fn}.j = ${runtimeTemplate.basicFunction( "chunkId, promises", hasJsMatcher !== false ? Template.indent([ "// import() chunk loading for javascript", `${lt} installedChunkData = ${RuntimeGlobals.hasOwnProperty}(installedChunks, chunkId) ? installedChunks[chunkId] : undefined;`, 'if(installedChunkData !== 0) { // 0 means "already installed".', Template.indent([ "", '// a Promise means "currently loading".', "if(installedChunkData) {", Template.indent([ "promises.push(installedChunkData[1]);" ]), "} else {", Template.indent([ hasJsMatcher === true ? "if(true) { // all chunks have JS" : `if(${hasJsMatcher("chunkId")}) {`, Template.indent([ "// setup Promise in chunk cache", `${lt} promise = ${importFunctionName}(${ compilation.outputOptions.publicPath === "auto" ? JSON.stringify(rootOutputDir) : RuntimeGlobals.publicPath } + ${ RuntimeGlobals.getChunkScriptFilename }(chunkId)).then(installChunk, ${runtimeTemplate.basicFunction( "e", [ "if(installedChunks[chunkId] !== 0) installedChunks[chunkId] = undefined;", "throw e;" ] )});`, `promise = Promise.race([promise, new Promise(${runtimeTemplate.expressionFunction( "installedChunkData = installedChunks[chunkId] = [resolve]", "resolve" )})])`, "promises.push(installedChunkData[1] = promise);" ]), hasJsMatcher === true ? "}" : "} else installedChunks[chunkId] = 0;" ]), "}" ]), "}" ]) : Template.indent(["installedChunks[chunkId] = 0;"]) )};` ]) : "// no chunk on demand loading", "", withPrefetch && hasJsMatcher !== false ? `${ RuntimeGlobals.prefetchChunkHandlers }.j = ${runtimeTemplate.basicFunction("chunkId", [ // prefetch is a browser-only resource hint; no-op without a DOM (e.g. node side of a universal build) isNeutralPlatform ? "if (typeof document === 'undefined') return;" : "", `if((!${ RuntimeGlobals.hasOwnProperty }(installedChunks, chunkId) || installedChunks[chunkId] === undefined) && ${ hasJsMatcher === true ? "true" : hasJsMatcher("chunkId") }) {`, Template.indent([ "installedChunks[chunkId] = null;", linkPrefetch.call( Template.asString([ `${cst} link = document.createElement('link');`, charset ? "link.charset = 'utf-8';" : "", crossOriginLoading ? `link.crossOrigin = ${JSON.stringify( crossOriginLoading )};` : "", `if (${RuntimeGlobals.scriptNonce}) {`, Template.indent( `link.setAttribute("nonce", ${RuntimeGlobals.scriptNonce});` ), "}", 'link.rel = "prefetch";', 'link.as = "script";', `link.href = ${RuntimeGlobals.publicPath} + ${RuntimeGlobals.getChunkScriptFilename}(chunkId);` ]), chunk ), "document.head.appendChild(link);" ]), "}" ])};` : "// no prefetching", "", withPreload && hasJsMatcher !== false ? `${ RuntimeGlobals.preloadChunkHandlers }.j = ${runtimeTemplate.basicFunction("chunkId", [ // preload is a browser-only resource hint; no-op without a DOM (e.g. node side of a universal build) isNeutralPlatform ? "if (typeof document === 'undefined') return;" : "", `if((!${ RuntimeGlobals.hasOwnProperty }(installedChunks, chunkId) || installedChunks[chunkId] === undefined) && ${ hasJsMatcher === true ? "true" : hasJsMatcher("chunkId") }) {`, Template.indent([ "installedChunks[chunkId] = null;", linkPreload.call( Template.asString([ `${cst} link = document.createElement('link');`, charset ? "link.charset = 'utf-8';" : "", `if (${RuntimeGlobals.scriptNonce}) {`, Template.indent( `link.setAttribute("nonce", ${RuntimeGlobals.scriptNonce});` ), "}", 'link.rel = "modulepreload";', `link.href = ${RuntimeGlobals.publicPath} + ${RuntimeGlobals.getChunkScriptFilename}(chunkId);`, crossOriginLoading ? crossOriginLoading === "use-credentials" ? 'link.crossOrigin = "use-credentials";' : Template.asString([ "if (link.href.indexOf(window.location.origin + '/') !== 0) {", Template.indent( `link.crossOrigin = ${JSON.stringify( crossOriginLoading )};` ), "}" ]) : "" ]), chunk ), "document.head.appendChild(link);" ]), "}" ])};` : "// no preloaded", "", withExternalInstallChunk ? Template.asString([ `${RuntimeGlobals.externalInstallChunk} = installChunk;` ]) : "// no external install chunk", "", withAnalyzableImport ? `${ RuntimeGlobals.analyzableChunkImport } = ${runtimeTemplate.basicFunction("chunkId, importFn", [ // A literal `import()` a foreign bundler can follow, wrapped to keep // `ensureChunk` timing and deduplication: resolved chunk → resolve now, in-flight → // reuse its promise, else run `importFn()` and install it. `${lt} installedChunkData = ${RuntimeGlobals.hasOwnProperty}(installedChunks, chunkId) ? installedChunks[chunkId] : undefined;`, "if(installedChunkData === 0) return Promise.resolve();", "if(installedChunkData) return installedChunkData[1];", `${lt} promise = importFn().then(installChunk, ${runtimeTemplate.basicFunction( "e", [ "if(installedChunks[chunkId] !== 0) installedChunks[chunkId] = undefined;", "throw e;" ] )});`, `promise = Promise.race([promise, new Promise(${runtimeTemplate.expressionFunction( "installedChunkData = installedChunks[chunkId] = [resolve]", "resolve" )})]);`, "return (installedChunkData[1] = promise);" ])};` : "// no analyzable chunk import", "", withOnChunkLoad ? `${ RuntimeGlobals.onChunksLoaded }.j = ${runtimeTemplate.returningFunction( "installedChunks[chunkId] === 0", "chunkId" )};` : "// no on chunks loaded", withHmr ? Template.asString([ generateJavascriptHMR("module"), "", "function loadUpdateChunk(chunkId, updatedModulesList) {", Template.indent([ `return new Promise(${runtimeTemplate.basicFunction( "resolve, reject", [ "// start update chunk loading", `${cst} url = ${RuntimeGlobals.publicPath} + ${RuntimeGlobals.getChunkUpdateScriptFilename}(chunkId);`, `${cst} onResolve = ${runtimeTemplate.basicFunction("obj", [ `${cst} updatedModules = obj.${RuntimeGlobals.esmModules};`, `${cst} updatedRuntime = obj.${RuntimeGlobals.esmRuntime};`, "if(updatedRuntime) currentUpdateRuntime.push(updatedRuntime);", "for(var moduleId in updatedModules) {", Template.indent([ `if(${RuntimeGlobals.hasOwnProperty}(updatedModules, moduleId)) {`, Template.indent([ "currentUpdate[moduleId] = updatedModules[moduleId];", `${runtimeTemplate.optionalChaining("updatedModulesList", "push(moduleId)")};` ]), "}" ]), "}", "resolve(obj);" ])};`, `${cst} onReject = ${runtimeTemplate.basicFunction("error", [ `${cst} errorMsg = error.message || 'unknown reason';`, "error.message = 'Loading hot update chunk ' + chunkId + ' failed.\\n(' + errorMsg + ')';", "error.name = 'ChunkLoadError';", "reject(error);" ])}`, `${cst} loadScript = ${runtimeTemplate.basicFunction( "url, onResolve, onReject", [ `return ${importFunctionName}(/* webpackIgnore: true */ url).then(onResolve).catch(onReject)` ] )}`, "loadScript(url, onResolve, onReject);" ] )});` ]), "}", "" ]) : "// no HMR", "", withHmrManifest ? Template.asString([ `${ RuntimeGlobals.hmrDownloadManifest } = ${runtimeTemplate.basicFunction("", [ `return ${importFunctionName}(/* webpackIgnore: true */ ${RuntimeGlobals.publicPath} + ${ RuntimeGlobals.getUpdateManifestFilename }()).then(${runtimeTemplate.basicFunction("obj", [ "return obj.default;" ])}, ${runtimeTemplate.basicFunction("error", [ "if(['MODULE_NOT_FOUND', 'ENOENT'].includes(error.code)) return;", "throw error;" ])});` ])};` ]) : "// no HMR manifest" ]); } } ModuleChunkLoadingRuntimeModule.getCompilationHooks = createHooksRegistry( createCompilationHooks ); module.exports = ModuleChunkLoadingRuntimeModule;