| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301 | /*	MIT License http://www.opensource.org/licenses/mit-license.php*/"use strict";const RuntimeGlobals = require("../RuntimeGlobals");const RuntimeModule = require("../RuntimeModule");const Template = require("../Template");const {	chunkHasJs,	getChunkFilenameTemplate} = require("../javascript/JavascriptModulesPlugin");const { getInitialChunkIds } = require("../javascript/StartupHelpers");const compileBooleanMatcher = require("../util/compileBooleanMatcher");const { getUndoPath } = require("../util/identifier");/** @typedef {import("../Chunk")} Chunk *//** @typedef {import("../ChunkGraph")} ChunkGraph *//** @typedef {import("../Compilation")} Compilation *//** @typedef {import("../Module").ReadOnlyRuntimeRequirements} ReadOnlyRuntimeRequirements */class ReadFileChunkLoadingRuntimeModule extends RuntimeModule {	/**	 * @param {ReadOnlyRuntimeRequirements} runtimeRequirements runtime requirements	 */	constructor(runtimeRequirements) {		super("readFile 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)};`;		}		return `${RuntimeGlobals.baseURI} = require("url").pathToFileURL(${			rootOutputDir				? `__dirname + ${JSON.stringify("/" + rootOutputDir)}`				: "__filename"		});`;	}	/**	 * @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 { runtimeTemplate } = compilation;		const fn = RuntimeGlobals.ensureChunkHandlers;		const withBaseURI = this.runtimeRequirements.has(RuntimeGlobals.baseURI);		const withExternalInstallChunk = this.runtimeRequirements.has(			RuntimeGlobals.externalInstallChunk		);		const withOnChunkLoad = this.runtimeRequirements.has(			RuntimeGlobals.onChunksLoaded		);		const withLoading = this.runtimeRequirements.has(			RuntimeGlobals.ensureChunkHandlers		);		const withHmr = this.runtimeRequirements.has(			RuntimeGlobals.hmrDownloadUpdateHandlers		);		const withHmrManifest = this.runtimeRequirements.has(			RuntimeGlobals.hmrDownloadManifest		);		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),			false		);		const stateExpression = withHmr			? `${RuntimeGlobals.hmrRuntimeStatePrefix}_readFileVm`			: undefined;		return Template.asString([			withBaseURI				? this._generateBaseUri(chunk, rootOutputDir)				: "// no baseURI",			"",			"// object to store loaded chunks",			'// "0" means "already loaded", Promise means loading',			`var installedChunks = ${				stateExpression ? `${stateExpression} = ${stateExpression} || ` : ""			}{`,			Template.indent(				Array.from(initialChunkIds, id => `${JSON.stringify(id)}: 0`).join(					",\n"				)			),			"};",			"",			withOnChunkLoad				? `${						RuntimeGlobals.onChunksLoaded					}.readFileVm = ${runtimeTemplate.returningFunction(						"installedChunks[chunkId] === 0",						"chunkId"					)};`				: "// no on chunks loaded",			"",			withLoading || withExternalInstallChunk				? `var installChunk = ${runtimeTemplate.basicFunction("chunk", [						"var moreModules = chunk.modules, chunkIds = chunk.ids, runtime = chunk.runtime;",						"for(var moduleId in moreModules) {",						Template.indent([							`if(${RuntimeGlobals.hasOwnProperty}(moreModules, moduleId)) {`,							Template.indent([								`${RuntimeGlobals.moduleFactories}[moduleId] = moreModules[moduleId];`							]),							"}"						]),						"}",						`if(runtime) runtime(${RuntimeGlobals.require});`,						"for(var i = 0; i < chunkIds.length; i++) {",						Template.indent([							"if(installedChunks[chunkIds[i]]) {",							Template.indent(["installedChunks[chunkIds[i]][0]();"]),							"}",							"installedChunks[chunkIds[i]] = 0;"						]),						"}",						withOnChunkLoad ? `${RuntimeGlobals.onChunksLoaded}();` : ""					])};`				: "// no chunk install function needed",			"",			withLoading				? Template.asString([						"// ReadFile + VM.run chunk loading for javascript",						`${fn}.readFileVm = function(chunkId, promises) {`,						hasJsMatcher !== false							? Template.indent([									"",									"var installedChunkData = installedChunks[chunkId];",									'if(installedChunkData !== 0) { // 0 means "already installed".',									Template.indent([										'// array of [resolve, reject, promise] means "currently loading"',										"if(installedChunkData) {",										Template.indent(["promises.push(installedChunkData[2]);"]),										"} else {",										Template.indent([											hasJsMatcher === true												? "if(true) { // all chunks have JS"												: `if(${hasJsMatcher("chunkId")}) {`,											Template.indent([												"// load the chunk and return promise to it",												"var promise = new Promise(function(resolve, reject) {",												Template.indent([													"installedChunkData = installedChunks[chunkId] = [resolve, reject];",													`var filename = require('path').join(__dirname, ${JSON.stringify(														rootOutputDir													)} + ${														RuntimeGlobals.getChunkScriptFilename													}(chunkId));`,													"require('fs').readFile(filename, 'utf-8', function(err, content) {",													Template.indent([														"if(err) return reject(err);",														"var chunk = {};",														"require('vm').runInThisContext('(function(exports, require, __dirname, __filename) {' + content + '\\n})', filename)" +															"(chunk, require, require('path').dirname(filename), filename);",														"installChunk(chunk);"													]),													"});"												]),												"});",												"promises.push(installedChunkData[2] = promise);"											]),											hasJsMatcher === true												? "}"												: "} else installedChunks[chunkId] = 0;"										]),										"}"									]),									"}"								])							: Template.indent(["installedChunks[chunkId] = 0;"]),						"};"					])				: "// no chunk loading",			"",			withExternalInstallChunk				? Template.asString([						`module.exports = ${RuntimeGlobals.require};`,						`${RuntimeGlobals.externalInstallChunk} = installChunk;`					])				: "// no external install chunk",			"",			withHmr				? Template.asString([						"function loadUpdateChunk(chunkId, updatedModulesList) {",						Template.indent([							"return new Promise(function(resolve, reject) {",							Template.indent([								`var filename = require('path').join(__dirname, ${JSON.stringify(									rootOutputDir								)} + ${RuntimeGlobals.getChunkUpdateScriptFilename}(chunkId));`,								"require('fs').readFile(filename, 'utf-8', function(err, content) {",								Template.indent([									"if(err) return reject(err);",									"var update = {};",									"require('vm').runInThisContext('(function(exports, require, __dirname, __filename) {' + content + '\\n})', filename)" +										"(update, require, require('path').dirname(filename), filename);",									"var updatedModules = update.modules;",									"var runtime = update.runtime;",									"for(var moduleId in updatedModules) {",									Template.indent([										`if(${RuntimeGlobals.hasOwnProperty}(updatedModules, moduleId)) {`,										Template.indent([											`currentUpdate[moduleId] = updatedModules[moduleId];`,											"if(updatedModulesList) updatedModulesList.push(moduleId);"										]),										"}"									]),									"}",									"if(runtime) currentUpdateRuntime.push(runtime);",									"resolve();"								]),								"});"							]),							"});"						]),						"}",						"",						Template.getFunctionContent(							require("../hmr/JavascriptHotModuleReplacement.runtime.js")						)							.replace(/\$key\$/g, "readFileVm")							.replace(/\$installedChunks\$/g, "installedChunks")							.replace(/\$loadUpdateChunk\$/g, "loadUpdateChunk")							.replace(/\$moduleCache\$/g, RuntimeGlobals.moduleCache)							.replace(/\$moduleFactories\$/g, RuntimeGlobals.moduleFactories)							.replace(								/\$ensureChunkHandlers\$/g,								RuntimeGlobals.ensureChunkHandlers							)							.replace(/\$hasOwnProperty\$/g, RuntimeGlobals.hasOwnProperty)							.replace(/\$hmrModuleData\$/g, RuntimeGlobals.hmrModuleData)							.replace(								/\$hmrDownloadUpdateHandlers\$/g,								RuntimeGlobals.hmrDownloadUpdateHandlers							)							.replace(								/\$hmrInvalidateModuleHandlers\$/g,								RuntimeGlobals.hmrInvalidateModuleHandlers							)					])				: "// no HMR",			"",			withHmrManifest				? Template.asString([						`${RuntimeGlobals.hmrDownloadManifest} = function() {`,						Template.indent([							"return new Promise(function(resolve, reject) {",							Template.indent([								`var filename = require('path').join(__dirname, ${JSON.stringify(									rootOutputDir								)} + ${RuntimeGlobals.getUpdateManifestFilename}());`,								"require('fs').readFile(filename, 'utf-8', function(err, content) {",								Template.indent([									"if(err) {",									Template.indent([										'if(err.code === "ENOENT") return resolve();',										"return reject(err);"									]),									"}",									"try { resolve(JSON.parse(content)); }",									"catch(e) { reject(e); }"								]),								"});"							]),							"});"						]),						"}"					])				: "// no HMR manifest"		]);	}}module.exports = ReadFileChunkLoadingRuntimeModule;
 |