| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 | /*	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 Template = require("../Template");const HelperRuntimeModule = require("./HelperRuntimeModule");/** @typedef {import("../Chunk")} Chunk *//** @typedef {import("../Compiler")} Compiler *//** * @typedef {Object} LoadScriptCompilationHooks * @property {SyncWaterfallHook<[string, Chunk]>} createScript *//** @type {WeakMap<Compilation, LoadScriptCompilationHooks>} */const compilationHooksMap = new WeakMap();class LoadScriptRuntimeModule extends HelperRuntimeModule {	/**	 * @param {Compilation} compilation the compilation	 * @returns {LoadScriptCompilationHooks} 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 = {				createScript: new SyncWaterfallHook(["source", "chunk"])			};			compilationHooksMap.set(compilation, hooks);		}		return hooks;	}	/**	 * @param {boolean=} withCreateScriptUrl use create script url for trusted types	 */	constructor(withCreateScriptUrl) {		super("load script");		this._withCreateScriptUrl = withCreateScriptUrl;	}	/**	 * @returns {string} runtime code	 */	generate() {		const { compilation } = this;		const { runtimeTemplate, outputOptions } = compilation;		const {			scriptType,			chunkLoadTimeout: loadTimeout,			crossOriginLoading,			uniqueName,			charset		} = outputOptions;		const fn = RuntimeGlobals.loadScript;		const { createScript } =			LoadScriptRuntimeModule.getCompilationHooks(compilation);		const code = Template.asString([			"script = document.createElement('script');",			scriptType ? `script.type = ${JSON.stringify(scriptType)};` : "",			charset ? "script.charset = 'utf-8';" : "",			`script.timeout = ${loadTimeout / 1000};`,			`if (${RuntimeGlobals.scriptNonce}) {`,			Template.indent(				`script.setAttribute("nonce", ${RuntimeGlobals.scriptNonce});`			),			"}",			uniqueName				? 'script.setAttribute("data-webpack", dataWebpackPrefix + key);'				: "",			`script.src = ${				this._withCreateScriptUrl					? `${RuntimeGlobals.createScriptUrl}(url)`					: "url"			};`,			crossOriginLoading				? crossOriginLoading === "use-credentials"					? 'script.crossOrigin = "use-credentials";'					: Template.asString([							"if (script.src.indexOf(window.location.origin + '/') !== 0) {",							Template.indent(								`script.crossOrigin = ${JSON.stringify(crossOriginLoading)};`							),							"}"					  ])				: ""		]);		return Template.asString([			"var inProgress = {};",			uniqueName				? `var dataWebpackPrefix = ${JSON.stringify(uniqueName + ":")};`				: "// data-webpack is not used as build has no uniqueName",			"// loadScript function to load a script via script tag",			`${fn} = ${runtimeTemplate.basicFunction("url, done, key, chunkId", [				"if(inProgress[url]) { inProgress[url].push(done); return; }",				"var script, needAttach;",				"if(key !== undefined) {",				Template.indent([					'var scripts = document.getElementsByTagName("script");',					"for(var i = 0; i < scripts.length; i++) {",					Template.indent([						"var s = scripts[i];",						`if(s.getAttribute("src") == url${							uniqueName								? ' || s.getAttribute("data-webpack") == dataWebpackPrefix + key'								: ""						}) { script = s; break; }`					]),					"}"				]),				"}",				"if(!script) {",				Template.indent([					"needAttach = true;",					createScript.call(code, this.chunk)				]),				"}",				"inProgress[url] = [done];",				"var onScriptComplete = " +					runtimeTemplate.basicFunction(						"prev, event",						Template.asString([							"// avoid mem leaks in IE.",							"script.onerror = script.onload = null;",							"clearTimeout(timeout);",							"var doneFns = inProgress[url];",							"delete inProgress[url];",							"script.parentNode && script.parentNode.removeChild(script);",							`doneFns && doneFns.forEach(${runtimeTemplate.returningFunction(								"fn(event)",								"fn"							)});`,							"if(prev) return prev(event);"						])					) +					";",				`var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), ${loadTimeout});`,				"script.onerror = onScriptComplete.bind(null, script.onerror);",				"script.onload = onScriptComplete.bind(null, script.onload);",				"needAttach && document.head.appendChild(script);"			])};`		]);	}}module.exports = LoadScriptRuntimeModule;
 |