| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421 | /*	MIT License http://www.opensource.org/licenses/mit-license.php*/"use strict";const { SyncWaterfallHook } = require("tapable");const Compilation = require("../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 { getUndoPath } = require("../util/identifier");/** @typedef {import("../../declarations/WebpackOptions").Environment} Environment *//** @typedef {import("../Chunk")} Chunk *//** @typedef {import("../ChunkGraph")} ChunkGraph *//** @typedef {import("../Module").ReadOnlyRuntimeRequirements} ReadOnlyRuntimeRequirements *//** * @typedef {object} JsonpCompilationPluginHooks * @property {SyncWaterfallHook<[string, Chunk]>} linkPreload * @property {SyncWaterfallHook<[string, Chunk]>} linkPrefetch *//** @type {WeakMap<Compilation, JsonpCompilationPluginHooks>} */const compilationHooksMap = new WeakMap();class ModuleChunkLoadingRuntimeModule extends RuntimeModule {	/**	 * @param {Compilation} compilation the compilation	 * @returns {JsonpCompilationPluginHooks} hooks	 */	static getCompilationHooks(compilation) {		if (!(compilation instanceof Compilation)) {			throw new TypeError(				"The 'compilation' argument must be an instance of Compilation"			);		}		let hooks = compilationHooksMap.get(compilation);		if (hooks === undefined) {			hooks = {				linkPreload: new SyncWaterfallHook(["source", "chunk"]),				linkPrefetch: new SyncWaterfallHook(["source", "chunk"])			};			compilationHooksMap.set(compilation, hooks);		}		return hooks;	}	/**	 * @param {ReadOnlyRuntimeRequirements} runtimeRequirements runtime requirements	 */	constructor(runtimeRequirements) {		super("import chunk loading", RuntimeModule.STAGE_ATTACH);		this._runtimeRequirements = runtimeRequirements;	}	/**	 * @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);`;	}	/**	 * @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 =			/** @type {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 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,			/** @type {string} */ (compilation.outputOptions.path),			true		);		const stateExpression = withHmr			? `${RuntimeGlobals.hmrRuntimeStatePrefix}_module`			: undefined;		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",			`var installedChunks = ${				stateExpression ? `${stateExpression} = ${stateExpression} || ` : ""			}{`,			Template.indent(				Array.from(initialChunkIds, id => `${JSON.stringify(id)}: 0`).join(					",\n"				)			),			"};",			"",			withLoading || withExternalInstallChunk				? `var installChunk = ${runtimeTemplate.basicFunction("data", [						runtimeTemplate.destructureObject(							["__webpack_ids__", "__webpack_modules__", "__webpack_runtime__"],							"data"						),						'// add "modules" to the modules object,',						'// then flag all "ids" as loaded and fire callback',						"var moduleId, chunkId, i = 0;",						"for(moduleId in __webpack_modules__) {",						Template.indent([							`if(${RuntimeGlobals.hasOwnProperty}(__webpack_modules__, moduleId)) {`,							Template.indent(								`${RuntimeGlobals.moduleFactories}[moduleId] = __webpack_modules__[moduleId];`							),							"}"						]),						"}",						`if(__webpack_runtime__) __webpack_runtime__(${RuntimeGlobals.require});`,						"for(;i < __webpack_ids__.length; i++) {",						Template.indent([							"chunkId = __webpack_ids__[i];",							`if(${RuntimeGlobals.hasOwnProperty}(installedChunks, chunkId) && installedChunks[chunkId]) {`,							Template.indent("installedChunks[chunkId][0]();"),							"}",							"installedChunks[__webpack_ids__[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",										`var 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",													`var 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;"														]													)});`,													`var 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", [						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([									"var 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", [						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([									"var 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",			"",			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",									`var url = ${RuntimeGlobals.publicPath} + ${RuntimeGlobals.getChunkUpdateScriptFilename}(chunkId);`,									`var onResolve = ${runtimeTemplate.basicFunction("obj", [										"var updatedModules = obj.__webpack_modules__;",										"var updatedRuntime = obj.__webpack_runtime__;",										"if(updatedRuntime) currentUpdateRuntime.push(updatedRuntime);",										"for(var moduleId in updatedModules) {",										Template.indent([											`if(${RuntimeGlobals.hasOwnProperty}(updatedModules, moduleId)) {`,											Template.indent([												"currentUpdate[moduleId] = updatedModules[moduleId];",												"if(updatedModulesList) updatedModulesList.push(moduleId);"											]),											"}"										]),										"}",										"resolve(obj);"									])};`,									`var onReject = ${runtimeTemplate.basicFunction("error", [										"var errorMsg = error.message || 'unknown reason';",										"error.message = 'Loading hot update chunk ' + chunkId + ' failed.\\n(' + errorMsg + ')';",										"error.name = 'ChunkLoadError';",										"reject(error);"									])}`,									`var 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;"							])});`						])};`					])				: "// no HMR manifest"		]);	}}module.exports = ModuleChunkLoadingRuntimeModule;
 |