| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568 | /*	MIT License http://www.opensource.org/licenses/mit-license.php	Author Tobias Koppers @sokra*/"use strict";const {	ConcatSource,	OriginalSource,	PrefixSource,	RawSource} = require("webpack-sources");const {	Tapable,	SyncWaterfallHook,	SyncHook,	SyncBailHook} = require("tapable");const Template = require("./Template");/** @typedef {import("webpack-sources").ConcatSource} ConcatSource *//** @typedef {import("webpack-sources").Source} Source *//** @typedef {import("./ModuleTemplate")} ModuleTemplate *//** @typedef {import("./Chunk")} Chunk *//** @typedef {import("./Module")} Module} *//** @typedef {import("./util/createHash").Hash} Hash} *//** @typedef {import("./Dependency").DependencyTemplate} DependencyTemplate} *//** * @typedef {Object} RenderManifestOptions * @property {Chunk} chunk the chunk used to render * @property {string} hash * @property {string} fullHash * @property {TODO} outputOptions * @property {{javascript: ModuleTemplate, webassembly: ModuleTemplate}} moduleTemplates * @property {Map<TODO, TODO>} dependencyTemplates */// require function shortcuts:// __webpack_require__.s = the module id of the entry point// __webpack_require__.c = the module cache// __webpack_require__.m = the module functions// __webpack_require__.p = the bundle public path// __webpack_require__.i = the identity function used for harmony imports// __webpack_require__.e = the chunk ensure function// __webpack_require__.d = the exported property define getter function// __webpack_require__.o = Object.prototype.hasOwnProperty.call// __webpack_require__.r = define compatibility on export// __webpack_require__.t = create a fake namespace object// __webpack_require__.n = compatibility get default export// __webpack_require__.h = the webpack hash// __webpack_require__.w = an object containing all installed WebAssembly.Instance export objects keyed by module id// __webpack_require__.oe = the uncaught error handler for the webpack runtime// __webpack_require__.nc = the script noncemodule.exports = class MainTemplate extends Tapable {	/**	 *	 * @param {TODO=} outputOptions output options for the MainTemplate	 */	constructor(outputOptions) {		super();		/** @type {TODO?} */		this.outputOptions = outputOptions || {};		this.hooks = {			/** @type {SyncWaterfallHook<TODO[], RenderManifestOptions>} */			renderManifest: new SyncWaterfallHook(["result", "options"]),			modules: new SyncWaterfallHook([				"modules",				"chunk",				"hash",				"moduleTemplate",				"dependencyTemplates"			]),			moduleObj: new SyncWaterfallHook([				"source",				"chunk",				"hash",				"moduleIdExpression"			]),			requireEnsure: new SyncWaterfallHook([				"source",				"chunk",				"hash",				"chunkIdExpression"			]),			bootstrap: new SyncWaterfallHook([				"source",				"chunk",				"hash",				"moduleTemplate",				"dependencyTemplates"			]),			localVars: new SyncWaterfallHook(["source", "chunk", "hash"]),			require: new SyncWaterfallHook(["source", "chunk", "hash"]),			requireExtensions: new SyncWaterfallHook(["source", "chunk", "hash"]),			/** @type {SyncWaterfallHook<string, Chunk, string>} */			beforeStartup: new SyncWaterfallHook(["source", "chunk", "hash"]),			/** @type {SyncWaterfallHook<string, Chunk, string>} */			startup: new SyncWaterfallHook(["source", "chunk", "hash"]),			/** @type {SyncWaterfallHook<string, Chunk, string>} */			afterStartup: new SyncWaterfallHook(["source", "chunk", "hash"]),			render: new SyncWaterfallHook([				"source",				"chunk",				"hash",				"moduleTemplate",				"dependencyTemplates"			]),			renderWithEntry: new SyncWaterfallHook(["source", "chunk", "hash"]),			moduleRequire: new SyncWaterfallHook([				"source",				"chunk",				"hash",				"moduleIdExpression"			]),			addModule: new SyncWaterfallHook([				"source",				"chunk",				"hash",				"moduleIdExpression",				"moduleExpression"			]),			currentHash: new SyncWaterfallHook(["source", "requestedLength"]),			assetPath: new SyncWaterfallHook(["path", "options", "assetInfo"]),			hash: new SyncHook(["hash"]),			hashForChunk: new SyncHook(["hash", "chunk"]),			globalHashPaths: new SyncWaterfallHook(["paths"]),			globalHash: new SyncBailHook(["chunk", "paths"]),			// TODO this should be moved somewhere else			// It's weird here			hotBootstrap: new SyncWaterfallHook(["source", "chunk", "hash"])		};		this.hooks.startup.tap("MainTemplate", (source, chunk, hash) => {			/** @type {string[]} */			const buf = [];			if (chunk.entryModule) {				buf.push("// Load entry module and return exports");				buf.push(					`return ${this.renderRequireFunctionForModule(						hash,						chunk,						JSON.stringify(chunk.entryModule.id)					)}(${this.requireFn}.s = ${JSON.stringify(chunk.entryModule.id)});`				);			}			return Template.asString(buf);		});		this.hooks.render.tap(			"MainTemplate",			(bootstrapSource, chunk, hash, moduleTemplate, dependencyTemplates) => {				const source = new ConcatSource();				source.add("/******/ (function(modules) { // webpackBootstrap\n");				source.add(new PrefixSource("/******/", bootstrapSource));				source.add("/******/ })\n");				source.add(					"/************************************************************************/\n"				);				source.add("/******/ (");				source.add(					this.hooks.modules.call(						new RawSource(""),						chunk,						hash,						moduleTemplate,						dependencyTemplates					)				);				source.add(")");				return source;			}		);		this.hooks.localVars.tap("MainTemplate", (source, chunk, hash) => {			return Template.asString([				source,				"// The module cache",				"var installedModules = {};"			]);		});		this.hooks.require.tap("MainTemplate", (source, chunk, hash) => {			return Template.asString([				source,				"// Check if module is in cache",				"if(installedModules[moduleId]) {",				Template.indent("return installedModules[moduleId].exports;"),				"}",				"// Create a new module (and put it into the cache)",				"var module = installedModules[moduleId] = {",				Template.indent(this.hooks.moduleObj.call("", chunk, hash, "moduleId")),				"};",				"",				Template.asString(					outputOptions.strictModuleExceptionHandling						? [								"// Execute the module function",								"var threw = true;",								"try {",								Template.indent([									`modules[moduleId].call(module.exports, module, module.exports, ${this.renderRequireFunctionForModule(										hash,										chunk,										"moduleId"									)});`,									"threw = false;"								]),								"} finally {",								Template.indent([									"if(threw) delete installedModules[moduleId];"								]),								"}"						  ]						: [								"// Execute the module function",								`modules[moduleId].call(module.exports, module, module.exports, ${this.renderRequireFunctionForModule(									hash,									chunk,									"moduleId"								)});`						  ]				),				"",				"// Flag the module as loaded",				"module.l = true;",				"",				"// Return the exports of the module",				"return module.exports;"			]);		});		this.hooks.moduleObj.tap(			"MainTemplate",			(source, chunk, hash, varModuleId) => {				return Template.asString(["i: moduleId,", "l: false,", "exports: {}"]);			}		);		this.hooks.requireExtensions.tap("MainTemplate", (source, chunk, hash) => {			const buf = [];			const chunkMaps = chunk.getChunkMaps();			// Check if there are non initial chunks which need to be imported using require-ensure			if (Object.keys(chunkMaps.hash).length) {				buf.push("// This file contains only the entry chunk.");				buf.push("// The chunk loading function for additional chunks");				buf.push(`${this.requireFn}.e = function requireEnsure(chunkId) {`);				buf.push(Template.indent("var promises = [];"));				buf.push(					Template.indent(						this.hooks.requireEnsure.call("", chunk, hash, "chunkId")					)				);				buf.push(Template.indent("return Promise.all(promises);"));				buf.push("};");			} else if (				chunk.hasModuleInGraph(m =>					m.blocks.some(b => b.chunkGroup && b.chunkGroup.chunks.length > 0)				)			) {				// There async blocks in the graph, so we need to add an empty requireEnsure				// function anyway. This can happen with multiple entrypoints.				buf.push("// The chunk loading function for additional chunks");				buf.push("// Since all referenced chunks are already included");				buf.push("// in this file, this function is empty here.");				buf.push(`${this.requireFn}.e = function requireEnsure() {`);				buf.push(Template.indent("return Promise.resolve();"));				buf.push("};");			}			buf.push("");			buf.push("// expose the modules object (__webpack_modules__)");			buf.push(`${this.requireFn}.m = modules;`);			buf.push("");			buf.push("// expose the module cache");			buf.push(`${this.requireFn}.c = installedModules;`);			buf.push("");			buf.push("// define getter function for harmony exports");			buf.push(`${this.requireFn}.d = function(exports, name, getter) {`);			buf.push(				Template.indent([					`if(!${this.requireFn}.o(exports, name)) {`,					Template.indent([						"Object.defineProperty(exports, name, { enumerable: true, get: getter });"					]),					"}"				])			);			buf.push("};");			buf.push("");			buf.push("// define __esModule on exports");			buf.push(`${this.requireFn}.r = function(exports) {`);			buf.push(				Template.indent([					"if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {",					Template.indent([						"Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });"					]),					"}",					"Object.defineProperty(exports, '__esModule', { value: true });"				])			);			buf.push("};");			buf.push("");			buf.push("// create a fake namespace object");			buf.push("// mode & 1: value is a module id, require it");			buf.push("// mode & 2: merge all properties of value into the ns");			buf.push("// mode & 4: return value when already ns object");			buf.push("// mode & 8|1: behave like require");			buf.push(`${this.requireFn}.t = function(value, mode) {`);			buf.push(				Template.indent([					`if(mode & 1) value = ${this.requireFn}(value);`,					`if(mode & 8) return value;`,					"if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;",					"var ns = Object.create(null);",					`${this.requireFn}.r(ns);`,					"Object.defineProperty(ns, 'default', { enumerable: true, value: value });",					"if(mode & 2 && typeof value != 'string') for(var key in value) " +						`${this.requireFn}.d(ns, key, function(key) { ` +						"return value[key]; " +						"}.bind(null, key));",					"return ns;"				])			);			buf.push("};");			buf.push("");			buf.push(				"// getDefaultExport function for compatibility with non-harmony modules"			);			buf.push(this.requireFn + ".n = function(module) {");			buf.push(				Template.indent([					"var getter = module && module.__esModule ?",					Template.indent([						"function getDefault() { return module['default']; } :",						"function getModuleExports() { return module; };"					]),					`${this.requireFn}.d(getter, 'a', getter);`,					"return getter;"				])			);			buf.push("};");			buf.push("");			buf.push("// Object.prototype.hasOwnProperty.call");			buf.push(				`${this.requireFn}.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };`			);			const publicPath = this.getPublicPath({				hash: hash			});			buf.push("");			buf.push("// __webpack_public_path__");			buf.push(`${this.requireFn}.p = ${JSON.stringify(publicPath)};`);			return Template.asString(buf);		});		this.requireFn = "__webpack_require__";	}	/**	 *	 * @param {RenderManifestOptions} options render manifest options	 * @returns {TODO[]} returns render manifest	 */	getRenderManifest(options) {		const result = [];		this.hooks.renderManifest.call(result, options);		return result;	}	/**	 * TODO webpack 5: remove moduleTemplate and dependencyTemplates	 * @param {string} hash hash to be used for render call	 * @param {Chunk} chunk Chunk instance	 * @param {ModuleTemplate} moduleTemplate ModuleTemplate instance for render	 * @param {Map<Function, DependencyTemplate>} dependencyTemplates dependency templates	 * @returns {string[]} the generated source of the bootstrap code	 */	renderBootstrap(hash, chunk, moduleTemplate, dependencyTemplates) {		const buf = [];		buf.push(			this.hooks.bootstrap.call(				"",				chunk,				hash,				moduleTemplate,				dependencyTemplates			)		);		buf.push(this.hooks.localVars.call("", chunk, hash));		buf.push("");		buf.push("// The require function");		buf.push(`function ${this.requireFn}(moduleId) {`);		buf.push(Template.indent(this.hooks.require.call("", chunk, hash)));		buf.push("}");		buf.push("");		buf.push(			Template.asString(this.hooks.requireExtensions.call("", chunk, hash))		);		buf.push("");		buf.push(Template.asString(this.hooks.beforeStartup.call("", chunk, hash)));		const afterStartupCode = Template.asString(			this.hooks.afterStartup.call("", chunk, hash)		);		if (afterStartupCode) {			// TODO webpack 5: this is a bit hacky to avoid a breaking change			// change it to a better way			buf.push("var startupResult = (function() {");		}		buf.push(Template.asString(this.hooks.startup.call("", chunk, hash)));		if (afterStartupCode) {			buf.push("})();");			buf.push(afterStartupCode);			buf.push("return startupResult;");		}		return buf;	}	/**	 * @param {string} hash hash to be used for render call	 * @param {Chunk} chunk Chunk instance	 * @param {ModuleTemplate} moduleTemplate ModuleTemplate instance for render	 * @param {Map<Function, DependencyTemplate>} dependencyTemplates dependency templates	 * @returns {ConcatSource} the newly generated source from rendering	 */	render(hash, chunk, moduleTemplate, dependencyTemplates) {		const buf = this.renderBootstrap(			hash,			chunk,			moduleTemplate,			dependencyTemplates		);		let source = this.hooks.render.call(			new OriginalSource(				Template.prefix(buf, " \t") + "\n",				"webpack/bootstrap"			),			chunk,			hash,			moduleTemplate,			dependencyTemplates		);		if (chunk.hasEntryModule()) {			source = this.hooks.renderWithEntry.call(source, chunk, hash);		}		if (!source) {			throw new Error(				"Compiler error: MainTemplate plugin 'render' should return something"			);		}		chunk.rendered = true;		return new ConcatSource(source, ";");	}	/**	 *	 * @param {string} hash hash for render fn	 * @param {Chunk} chunk Chunk instance for require	 * @param {(number|string)=} varModuleId module id	 * @returns {TODO} the moduleRequire hook call return signature	 */	renderRequireFunctionForModule(hash, chunk, varModuleId) {		return this.hooks.moduleRequire.call(			this.requireFn,			chunk,			hash,			varModuleId		);	}	/**	 *	 * @param {string} hash hash for render add fn	 * @param {Chunk} chunk Chunk instance for require add fn	 * @param {(string|number)=} varModuleId module id	 * @param {Module} varModule Module instance	 * @returns {TODO} renderAddModule call	 */	renderAddModule(hash, chunk, varModuleId, varModule) {		return this.hooks.addModule.call(			`modules[${varModuleId}] = ${varModule};`,			chunk,			hash,			varModuleId,			varModule		);	}	/**	 *	 * @param {string} hash string hash	 * @param {number=} length length	 * @returns {string} call hook return	 */	renderCurrentHashCode(hash, length) {		length = length || Infinity;		return this.hooks.currentHash.call(			JSON.stringify(hash.substr(0, length)),			length		);	}	/**	 *	 * @param {object} options get public path options	 * @returns {string} hook call	 */	getPublicPath(options) {		return this.hooks.assetPath.call(			this.outputOptions.publicPath || "",			options		);	}	getAssetPath(path, options) {		return this.hooks.assetPath.call(path, options);	}	getAssetPathWithInfo(path, options) {		const assetInfo = {};		// TODO webpack 5: refactor assetPath hook to receive { path, info } object		const newPath = this.hooks.assetPath.call(path, options, assetInfo);		return { path: newPath, info: assetInfo };	}	/**	 * Updates hash with information from this template	 * @param {Hash} hash the hash to update	 * @returns {void}	 */	updateHash(hash) {		hash.update("maintemplate");		hash.update("3");		this.hooks.hash.call(hash);	}	/**	 * TODO webpack 5: remove moduleTemplate and dependencyTemplates	 * Updates hash with chunk-specific information from this template	 * @param {Hash} hash the hash to update	 * @param {Chunk} chunk the chunk	 * @param {ModuleTemplate} moduleTemplate ModuleTemplate instance for render	 * @param {Map<Function, DependencyTemplate>} dependencyTemplates dependency templates	 * @returns {void}	 */	updateHashForChunk(hash, chunk, moduleTemplate, dependencyTemplates) {		this.updateHash(hash);		this.hooks.hashForChunk.call(hash, chunk);		for (const line of this.renderBootstrap(			"0000",			chunk,			moduleTemplate,			dependencyTemplates		)) {			hash.update(line);		}	}	useChunkHash(chunk) {		const paths = this.hooks.globalHashPaths.call([]);		return !this.hooks.globalHash.call(chunk, paths);	}};
 |