| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321 | /*	MIT License http://www.opensource.org/licenses/mit-license.php	Author Tobias Koppers @sokra*/"use strict";const Template = require("../Template");module.exports = class NodeMainTemplatePlugin {	constructor(asyncChunkLoading) {		this.asyncChunkLoading = asyncChunkLoading;	}	apply(mainTemplate) {		const needChunkOnDemandLoadingCode = chunk => {			for (const chunkGroup of chunk.groupsIterable) {				if (chunkGroup.getNumberOfChildren() > 0) return true;			}			return false;		};		const asyncChunkLoading = this.asyncChunkLoading;		mainTemplate.hooks.localVars.tap(			"NodeMainTemplatePlugin",			(source, chunk) => {				if (needChunkOnDemandLoadingCode(chunk)) {					return Template.asString([						source,						"",						"// object to store loaded chunks",						'// "0" means "already loaded"',						"var installedChunks = {",						Template.indent(							chunk.ids.map(id => `${JSON.stringify(id)}: 0`).join(",\n")						),						"};"					]);				}				return source;			}		);		mainTemplate.hooks.requireExtensions.tap(			"NodeMainTemplatePlugin",			(source, chunk) => {				if (needChunkOnDemandLoadingCode(chunk)) {					return Template.asString([						source,						"",						"// uncaught error handler for webpack runtime",						`${mainTemplate.requireFn}.oe = function(err) {`,						Template.indent([							"process.nextTick(function() {",							Template.indent(								"throw err; // catch this error by using import().catch()"							),							"});"						]),						"};"					]);				}				return source;			}		);		mainTemplate.hooks.requireEnsure.tap(			"NodeMainTemplatePlugin",			(source, chunk, hash) => {				const chunkFilename = mainTemplate.outputOptions.chunkFilename;				const chunkMaps = chunk.getChunkMaps();				const insertMoreModules = [					"var moreModules = chunk.modules, chunkIds = chunk.ids;",					"for(var moduleId in moreModules) {",					Template.indent(						mainTemplate.renderAddModule(							hash,							chunk,							"moduleId",							"moreModules[moduleId]"						)					),					"}"				];				if (asyncChunkLoading) {					return Template.asString([						source,						"",						"// ReadFile + VM.run chunk loading for javascript",						"",						"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([								"// 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, " +										mainTemplate.getAssetPath(											JSON.stringify(`/${chunkFilename}`),											{												hash: `" + ${mainTemplate.renderCurrentHashCode(													hash												)} + "`,												hashWithLength: length =>													`" + ${mainTemplate.renderCurrentHashCode(														hash,														length													)} + "`,												chunk: {													id: '" + chunkId + "',													hash: `" + ${JSON.stringify(														chunkMaps.hash													)}[chunkId] + "`,													hashWithLength: length => {														const shortChunkHashMap = {};														for (const chunkId of Object.keys(chunkMaps.hash)) {															if (typeof chunkMaps.hash[chunkId] === "string") {																shortChunkHashMap[chunkId] = chunkMaps.hash[																	chunkId																].substr(0, length);															}														}														return `" + ${JSON.stringify(															shortChunkHashMap														)}[chunkId] + "`;													},													contentHash: {														javascript: `" + ${JSON.stringify(															chunkMaps.contentHash.javascript														)}[chunkId] + "`													},													contentHashWithLength: {														javascript: length => {															const shortContentHashMap = {};															const contentHash =																chunkMaps.contentHash.javascript;															for (const chunkId of Object.keys(contentHash)) {																if (typeof contentHash[chunkId] === "string") {																	shortContentHashMap[chunkId] = contentHash[																		chunkId																	].substr(0, length);																}															}															return `" + ${JSON.stringify(																shortContentHashMap															)}[chunkId] + "`;														}													},													name: `" + (${JSON.stringify(														chunkMaps.name													)}[chunkId]||chunkId) + "`												},												contentHashType: "javascript"											}										) +										");",									"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);"										]											.concat(insertMoreModules)											.concat([												"var callbacks = [];",												"for(var i = 0; i < chunkIds.length; i++) {",												Template.indent([													"if(installedChunks[chunkIds[i]])",													Template.indent([														"callbacks = callbacks.concat(installedChunks[chunkIds[i]][0]);"													]),													"installedChunks[chunkIds[i]] = 0;"												]),												"}",												"for(i = 0; i < callbacks.length; i++)",												Template.indent("callbacks[i]();")											])									),									"});"								]),								"});",								"promises.push(installedChunkData[2] = promise);"							]),							"}"						]),						"}"					]);				} else {					const request = mainTemplate.getAssetPath(						JSON.stringify(`./${chunkFilename}`),						{							hash: `" + ${mainTemplate.renderCurrentHashCode(hash)} + "`,							hashWithLength: length =>								`" + ${mainTemplate.renderCurrentHashCode(hash, length)} + "`,							chunk: {								id: '" + chunkId + "',								hash: `" + ${JSON.stringify(chunkMaps.hash)}[chunkId] + "`,								hashWithLength: length => {									const shortChunkHashMap = {};									for (const chunkId of Object.keys(chunkMaps.hash)) {										if (typeof chunkMaps.hash[chunkId] === "string") {											shortChunkHashMap[chunkId] = chunkMaps.hash[												chunkId											].substr(0, length);										}									}									return `" + ${JSON.stringify(										shortChunkHashMap									)}[chunkId] + "`;								},								contentHash: {									javascript: `" + ${JSON.stringify(										chunkMaps.contentHash.javascript									)}[chunkId] + "`								},								contentHashWithLength: {									javascript: length => {										const shortContentHashMap = {};										const contentHash = chunkMaps.contentHash.javascript;										for (const chunkId of Object.keys(contentHash)) {											if (typeof contentHash[chunkId] === "string") {												shortContentHashMap[chunkId] = contentHash[													chunkId												].substr(0, length);											}										}										return `" + ${JSON.stringify(											shortContentHashMap										)}[chunkId] + "`;									}								},								name: `" + (${JSON.stringify(									chunkMaps.name								)}[chunkId]||chunkId) + "`							},							contentHashType: "javascript"						}					);					return Template.asString([						source,						"",						"// require() chunk loading for javascript",						"",						'// "0" is the signal for "already loaded"',						"if(installedChunks[chunkId] !== 0) {",						Template.indent(							[`var chunk = require(${request});`]								.concat(insertMoreModules)								.concat([									"for(var i = 0; i < chunkIds.length; i++)",									Template.indent("installedChunks[chunkIds[i]] = 0;")								])						),						"}"					]);				}			}		);		mainTemplate.hooks.hotBootstrap.tap(			"NodeMainTemplatePlugin",			(source, chunk, hash) => {				const hotUpdateChunkFilename =					mainTemplate.outputOptions.hotUpdateChunkFilename;				const hotUpdateMainFilename =					mainTemplate.outputOptions.hotUpdateMainFilename;				const chunkMaps = chunk.getChunkMaps();				const currentHotUpdateChunkFilename = mainTemplate.getAssetPath(					JSON.stringify(hotUpdateChunkFilename),					{						hash: `" + ${mainTemplate.renderCurrentHashCode(hash)} + "`,						hashWithLength: length =>							`" + ${mainTemplate.renderCurrentHashCode(hash, length)} + "`,						chunk: {							id: '" + chunkId + "',							hash: `" + ${JSON.stringify(chunkMaps.hash)}[chunkId] + "`,							hashWithLength: length => {								const shortChunkHashMap = {};								for (const chunkId of Object.keys(chunkMaps.hash)) {									if (typeof chunkMaps.hash[chunkId] === "string") {										shortChunkHashMap[chunkId] = chunkMaps.hash[chunkId].substr(											0,											length										);									}								}								return `" + ${JSON.stringify(shortChunkHashMap)}[chunkId] + "`;							},							name: `" + (${JSON.stringify(								chunkMaps.name							)}[chunkId]||chunkId) + "`						}					}				);				const currentHotUpdateMainFilename = mainTemplate.getAssetPath(					JSON.stringify(hotUpdateMainFilename),					{						hash: `" + ${mainTemplate.renderCurrentHashCode(hash)} + "`,						hashWithLength: length =>							`" + ${mainTemplate.renderCurrentHashCode(hash, length)} + "`					}				);				return Template.getFunctionContent(					asyncChunkLoading						? require("./NodeMainTemplateAsync.runtime")						: require("./NodeMainTemplate.runtime")				)					.replace(/\$require\$/g, mainTemplate.requireFn)					.replace(/\$hotMainFilename\$/g, currentHotUpdateMainFilename)					.replace(/\$hotChunkFilename\$/g, currentHotUpdateChunkFilename);			}		);		mainTemplate.hooks.hash.tap("NodeMainTemplatePlugin", hash => {			hash.update("node");			hash.update("4");		});	}};
 |