code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const CachedInputFileSystem = require("enhanced-resolve").CachedInputFileSystem;
const fs = require("graceful-fs");
const createConsoleLogger = require("../logging/createConsoleLogger");
const NodeWatchFileSystem = require("./NodeWatchFileSystem");
const nodeConsole = require("./nodeConsole");

/** @typedef {import("../../declarations/WebpackOptions").InfrastructureLogging} InfrastructureLogging */
/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../util/fs").InputFileSystem} InputFileSystem */

class NodeEnvironmentPlugin {
	/**
	 * @param {object} options options
	 * @param {InfrastructureLogging} options.infrastructureLogging infrastructure logging options
	 */
	constructor(options) {
		this.options = options;
	}

	/**
	 * Apply the plugin
	 * @param {Compiler} compiler the compiler instance
	 * @returns {void}
	 */
	apply(compiler) {
		const { infrastructureLogging } = this.options;
		compiler.infrastructureLogger = createConsoleLogger({
			level: infrastructureLogging.level || "info",
			debug: infrastructureLogging.debug || false,
			console:
				infrastructureLogging.console ||
				nodeConsole({
					colors: infrastructureLogging.colors,
					appendOnly: infrastructureLogging.appendOnly,
					stream:
						/** @type {NodeJS.WritableStream} */
						(infrastructureLogging.stream)
				})
		});
		compiler.inputFileSystem = new CachedInputFileSystem(fs, 60000);
		const inputFileSystem =
			/** @type {InputFileSystem} */
			(compiler.inputFileSystem);
		compiler.outputFileSystem = fs;
		compiler.intermediateFileSystem = fs;
		compiler.watchFileSystem = new NodeWatchFileSystem(inputFileSystem);
		compiler.hooks.beforeRun.tap("NodeEnvironmentPlugin", compiler => {
			if (
				compiler.inputFileSystem === inputFileSystem &&
				inputFileSystem.purge
			) {
				compiler.fsStartTime = Date.now();
				inputFileSystem.purge();
			}
		});
	}
}

module.exports = NodeEnvironmentPlugin;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

/** @typedef {import("../Compiler")} Compiler */

class NodeSourcePlugin {
	/**
	 * Apply the plugin
	 * @param {Compiler} compiler the compiler instance
	 * @returns {void}
	 */
	apply(compiler) {}
}

module.exports = NodeSourcePlugin;

license: mit


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const ExternalsPlugin = require("../ExternalsPlugin");

/** @typedef {import("../Compiler")} Compiler */

const builtins = [
	"assert",
	"assert/strict",
	"async_hooks",
	"buffer",
	"child_process",
	"cluster",
	"console",
	"constants",
	"crypto",
	"dgram",
	"diagnostics_channel",
	"dns",
	"dns/promises",
	"domain",
	"events",
	"fs",
	"fs/promises",
	"http",
	"http2",
	"https",
	"inspector",
	"inspector/promises",
	"module",
	"net",
	"os",
	"path",
	"path/posix",
	"path/win32",
	"perf_hooks",
	"process",
	"punycode",
	"querystring",
	"readline",
	"readline/promises",
	"repl",
	"stream",
	"stream/consumers",
	"stream/promises",
	"stream/web",
	"string_decoder",
	"sys",
	"timers",
	"timers/promises",
	"tls",
	"trace_events",
	"tty",
	"url",
	"util",
	"util/types",
	"v8",
	"vm",
	"wasi",
	"worker_threads",
	"zlib",
	/^node:/,

	// cspell:word pnpapi
	// Yarn PnP adds pnpapi as "builtin"
	"pnpapi"
];

class NodeTargetPlugin {
	/**
	 * Apply the plugin
	 * @param {Compiler} compiler the compiler instance
	 * @returns {void}
	 */
	apply(compiler) {
		new ExternalsPlugin("node-commonjs", builtins).apply(compiler);
	}
}

module.exports = NodeTargetPlugin;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const CommonJsChunkFormatPlugin = require("../javascript/CommonJsChunkFormatPlugin");
const EnableChunkLoadingPlugin = require("../javascript/EnableChunkLoadingPlugin");

/** @typedef {import("../Compiler")} Compiler */

/**
 * @typedef {object} NodeTemplatePluginOptions
 * @property {boolean} [asyncChunkLoading] enable async chunk loading
 */

class NodeTemplatePlugin {
	/**
	 * @param {NodeTemplatePluginOptions} [options] options object
	 */
	constructor(options = {}) {
		this._options = options;
	}

	/**
	 * Apply the plugin
	 * @param {Compiler} compiler the compiler instance
	 * @returns {void}
	 */
	apply(compiler) {
		const chunkLoading = this._options.asyncChunkLoading
			? "async-node"
			: "require";
		compiler.options.output.chunkLoading = chunkLoading;
		new CommonJsChunkFormatPlugin().apply(compiler);
		new EnableChunkLoadingPlugin(chunkLoading).apply(compiler);
	}
}

module.exports = NodeTemplatePlugin;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const util = require("util");
const Watchpack = require("watchpack");

/** @typedef {import("../../declarations/WebpackOptions").WatchOptions} WatchOptions */
/** @typedef {import("../FileSystemInfo").FileSystemInfoEntry} FileSystemInfoEntry */
/** @typedef {import("../util/fs").InputFileSystem} InputFileSystem */
/** @typedef {import("../util/fs").WatchFileSystem} WatchFileSystem */
/** @typedef {import("../util/fs").WatchMethod} WatchMethod */
/** @typedef {import("../util/fs").Watcher} Watcher */

class NodeWatchFileSystem {
	/**
	 * @param {InputFileSystem} inputFileSystem input filesystem
	 */
	constructor(inputFileSystem) {
		this.inputFileSystem = inputFileSystem;
		this.watcherOptions = {
			aggregateTimeout: 0
		};
		this.watcher = new Watchpack(this.watcherOptions);
	}

	/**
	 * @param {Iterable<string>} files watched files
	 * @param {Iterable<string>} directories watched directories
	 * @param {Iterable<string>} missing watched existence entries
	 * @param {number} startTime timestamp of start time
	 * @param {WatchOptions} options options object
	 * @param {function(Error | null, Map<string, FileSystemInfoEntry>, Map<string, FileSystemInfoEntry>, Set<string>, Set<string>): void} callback aggregated callback
	 * @param {function(string, number): void} callbackUndelayed callback when the first change was detected
	 * @returns {Watcher} a watcher
	 */
	watch(
		files,
		directories,
		missing,
		startTime,
		options,
		callback,
		callbackUndelayed
	) {
		if (!files || typeof files[Symbol.iterator] !== "function") {
			throw new Error("Invalid arguments: 'files'");
		}
		if (!directories || typeof directories[Symbol.iterator] !== "function") {
			throw new Error("Invalid arguments: 'directories'");
		}
		if (!missing || typeof missing[Symbol.iterator] !== "function") {
			throw new Error("Invalid arguments: 'missing'");
		}
		if (typeof callback !== "function") {
			throw new Error("Invalid arguments: 'callback'");
		}
		if (typeof startTime !== "number" && startTime) {
			throw new Error("Invalid arguments: 'startTime'");
		}
		if (typeof options !== "object") {
			throw new Error("Invalid arguments: 'options'");
		}
		if (typeof callbackUndelayed !== "function" && callbackUndelayed) {
			throw new Error("Invalid arguments: 'callbackUndelayed'");
		}
		const oldWatcher = this.watcher;
		this.watcher = new Watchpack(options);

		if (callbackUndelayed) {
			this.watcher.once("change", callbackUndelayed);
		}

		const fetchTimeInfo = () => {
			const fileTimeInfoEntries = new Map();
			const contextTimeInfoEntries = new Map();
			if (this.watcher) {
				this.watcher.collectTimeInfoEntries(
					fileTimeInfoEntries,
					contextTimeInfoEntries
				);
			}
			return { fileTimeInfoEntries, contextTimeInfoEntries };
		};
		this.watcher.once(
			"aggregated",
			/**
			 * @param {Set<string>} changes changes
			 * @param {Set<string>} removals removals
			 */
			(changes, removals) => {
				// pause emitting events (avoids clearing aggregated changes and removals on timeout)
				this.watcher.pause();

				const fs = this.inputFileSystem;
				if (fs && fs.purge) {
					for (const item of changes) {
						fs.purge(item);
					}
					for (const item of removals) {
						fs.purge(item);
					}
				}
				const { fileTimeInfoEntries, contextTimeInfoEntries } = fetchTimeInfo();
				callback(
					null,
					fileTimeInfoEntries,
					contextTimeInfoEntries,
					changes,
					removals
				);
			}
		);

		this.watcher.watch({ files, directories, missing, startTime });

		if (oldWatcher) {
			oldWatcher.close();
		}
		return {
			close: () => {
				if (this.watcher) {
					this.watcher.close();
					this.watcher = null;
				}
			},
			pause: () => {
				if (this.watcher) {
					this.watcher.pause();
				}
			},
			getAggregatedRemovals: util.deprecate(
				() => {
					const items = this.watcher && this.watcher.aggregatedRemovals;
					const fs = this.inputFileSystem;
					if (items && fs && fs.purge) {
						for (const item of items) {
							fs.purge(item);
						}
					}
					return items;
				},
				"Watcher.getAggregatedRemovals is deprecated in favor of Watcher.getInfo since that's more performant.",
				"DEP_WEBPACK_WATCHER_GET_AGGREGATED_REMOVALS"
			),
			getAggregatedChanges: util.deprecate(
				() => {
					const items = this.watcher && this.watcher.aggregatedChanges;
					const fs = this.inputFileSystem;
					if (items && fs && fs.purge) {
						for (const item of items) {
							fs.purge(item);
						}
					}
					return items;
				},
				"Watcher.getAggregatedChanges is deprecated in favor of Watcher.getInfo since that's more performant.",
				"DEP_WEBPACK_WATCHER_GET_AGGREGATED_CHANGES"
			),
			getFileTimeInfoEntries: util.deprecate(
				() => {
					return fetchTimeInfo().fileTimeInfoEntries;
				},
				"Watcher.getFileTimeInfoEntries is deprecated in favor of Watcher.getInfo since that's more performant.",
				"DEP_WEBPACK_WATCHER_FILE_TIME_INFO_ENTRIES"
			),
			getContextTimeInfoEntries: util.deprecate(
				() => {
					return fetchTimeInfo().contextTimeInfoEntries;
				},
				"Watcher.getContextTimeInfoEntries is deprecated in favor of Watcher.getInfo since that's more performant.",
				"DEP_WEBPACK_WATCHER_CONTEXT_TIME_INFO_ENTRIES"
			),
			getInfo: () => {
				const removals = this.watcher && this.watcher.aggregatedRemovals;
				const changes = this.watcher && this.watcher.aggregatedChanges;
				const fs = this.inputFileSystem;
				if (fs && fs.purge) {
					if (removals) {
						for (const item of removals) {
							fs.purge(item);
						}
					}
					if (changes) {
						for (const item of changes) {
							fs.purge(item);
						}
					}
				}
				const { fileTimeInfoEntries, contextTimeInfoEntries } = fetchTimeInfo();
				return {
					changes,
					removals,
					fileTimeInfoEntries,
					contextTimeInfoEntries
				};
			}
		};
	}
}

module.exports = NodeWatchFileSystem;


code:
/*
	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;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const { WEBASSEMBLY_MODULE_TYPE_ASYNC } = require("../ModuleTypeConstants");
const RuntimeGlobals = require("../RuntimeGlobals");
const Template = require("../Template");
const AsyncWasmLoadingRuntimeModule = require("../wasm-async/AsyncWasmLoadingRuntimeModule");

/** @typedef {import("../Chunk")} Chunk */
/** @typedef {import("../Compiler")} Compiler */

class ReadFileCompileAsyncWasmPlugin {
	constructor({ type = "async-node", import: useImport = false } = {}) {
		this._type = type;
		this._import = useImport;
	}
	/**
	 * Apply the plugin
	 * @param {Compiler} compiler the compiler instance
	 * @returns {void}
	 */
	apply(compiler) {
		compiler.hooks.thisCompilation.tap(
			"ReadFileCompileAsyncWasmPlugin",
			compilation => {
				const globalWasmLoading = compilation.outputOptions.wasmLoading;
				/**
				 * @param {Chunk} chunk chunk
				 * @returns {boolean} true, if wasm loading is enabled for the chunk
				 */
				const isEnabledForChunk = chunk => {
					const options = chunk.getEntryOptions();
					const wasmLoading =
						options && options.wasmLoading !== undefined
							? options.wasmLoading
							: globalWasmLoading;
					return wasmLoading === this._type;
				};
				const { importMetaName } = compilation.outputOptions;
				/**
				 * @type {(path: string) => string}
				 */
				const generateLoadBinaryCode = this._import
					? path =>
							Template.asString([
								"Promise.all([import('fs'), import('url')]).then(([{ readFile }, { URL }]) => new Promise((resolve, reject) => {",
								Template.indent([
									`readFile(new URL(${path}, ${importMetaName}.url), (err, buffer) => {`,
									Template.indent([
										"if (err) return reject(err);",
										"",
										"// Fake fetch response",
										"resolve({",
										Template.indent(["arrayBuffer() { return buffer; }"]),
										"});"
									]),
									"});"
								]),
								"}))"
							])
					: path =>
							Template.asString([
								"new Promise(function (resolve, reject) {",
								Template.indent([
									"try {",
									Template.indent([
										"var { readFile } = require('fs');",
										"var { join } = require('path');",
										"",
										`readFile(join(__dirname, ${path}), function(err, buffer){`,
										Template.indent([
											"if (err) return reject(err);",
											"",
											"// Fake fetch response",
											"resolve({",
											Template.indent(["arrayBuffer() { return buffer; }"]),
											"});"
										]),
										"});"
									]),
									"} catch (err) { reject(err); }"
								]),
								"})"
							]);

				compilation.hooks.runtimeRequirementInTree
					.for(RuntimeGlobals.instantiateWasm)
					.tap("ReadFileCompileAsyncWasmPlugin", (chunk, set) => {
						if (!isEnabledForChunk(chunk)) return;
						const chunkGraph = compilation.chunkGraph;
						if (
							!chunkGraph.hasModuleInGraph(
								chunk,
								m => m.type === WEBASSEMBLY_MODULE_TYPE_ASYNC
							)
						) {
							return;
						}
						set.add(RuntimeGlobals.publicPath);
						compilation.addRuntimeModule(
							chunk,
							new AsyncWasmLoadingRuntimeModule({
								generateLoadBinaryCode,
								supportsStreaming: false
							})
						);
					});
			}
		);
	}
}

module.exports = ReadFileCompileAsyncWasmPlugin;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const { WEBASSEMBLY_MODULE_TYPE_SYNC } = require("../ModuleTypeConstants");
const RuntimeGlobals = require("../RuntimeGlobals");
const Template = require("../Template");
const WasmChunkLoadingRuntimeModule = require("../wasm-sync/WasmChunkLoadingRuntimeModule");

/** @typedef {import("../Chunk")} Chunk */
/** @typedef {import("../Compiler")} Compiler */

/**
 * @typedef {object} ReadFileCompileWasmPluginOptions
 * @property {boolean} [mangleImports] mangle imports
 */

// TODO webpack 6 remove

class ReadFileCompileWasmPlugin {
	/**
	 * @param {ReadFileCompileWasmPluginOptions} [options] options object
	 */
	constructor(options = {}) {
		this.options = options;
	}

	/**
	 * Apply the plugin
	 * @param {Compiler} compiler the compiler instance
	 * @returns {void}
	 */
	apply(compiler) {
		compiler.hooks.thisCompilation.tap(
			"ReadFileCompileWasmPlugin",
			compilation => {
				const globalWasmLoading = compilation.outputOptions.wasmLoading;
				/**
				 * @param {Chunk} chunk chunk
				 * @returns {boolean} true, when wasm loading is enabled for the chunk
				 */
				const isEnabledForChunk = chunk => {
					const options = chunk.getEntryOptions();
					const wasmLoading =
						options && options.wasmLoading !== undefined
							? options.wasmLoading
							: globalWasmLoading;
					return wasmLoading === "async-node";
				};
				/**
				 * @param {string} path path to wasm file
				 * @returns {string} generated code to load the wasm file
				 */
				const generateLoadBinaryCode = path =>
					Template.asString([
						"new Promise(function (resolve, reject) {",
						Template.indent([
							"var { readFile } = require('fs');",
							"var { join } = require('path');",
							"",
							"try {",
							Template.indent([
								`readFile(join(__dirname, ${path}), function(err, buffer){`,
								Template.indent([
									"if (err) return reject(err);",
									"",
									"// Fake fetch response",
									"resolve({",
									Template.indent(["arrayBuffer() { return buffer; }"]),
									"});"
								]),
								"});"
							]),
							"} catch (err) { reject(err); }"
						]),
						"})"
					]);

				compilation.hooks.runtimeRequirementInTree
					.for(RuntimeGlobals.ensureChunkHandlers)
					.tap("ReadFileCompileWasmPlugin", (chunk, set) => {
						if (!isEnabledForChunk(chunk)) return;
						const chunkGraph = compilation.chunkGraph;
						if (
							!chunkGraph.hasModuleInGraph(
								chunk,
								m => m.type === WEBASSEMBLY_MODULE_TYPE_SYNC
							)
						) {
							return;
						}
						set.add(RuntimeGlobals.moduleCache);
						compilation.addRuntimeModule(
							chunk,
							new WasmChunkLoadingRuntimeModule({
								generateLoadBinaryCode,
								supportsStreaming: false,
								mangleImports: this.options.mangleImports,
								runtimeRequirements: set
							})
						);
					});
			}
		);
	}
}

module.exports = ReadFileCompileWasmPlugin;


code:
/*
	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 RequireChunkLoadingRuntimeModule extends RuntimeModule {
	/**
	 * @param {ReadOnlyRuntimeRequirements} runtimeRequirements runtime requirements
	 */
	constructor(runtimeRequirements) {
		super("require 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),
			true
		);

		const stateExpression = withHmr
			? `${RuntimeGlobals.hmrRuntimeStatePrefix}_require`
			: undefined;

		return Template.asString([
			withBaseURI
				? this._generateBaseUri(chunk, rootOutputDir)
				: "// no baseURI",
			"",
			"// object to store loaded chunks",
			'// "1" means "loaded", otherwise not loaded yet',
			`var installedChunks = ${
				stateExpression ? `${stateExpression} = ${stateExpression} || ` : ""
			}{`,
			Template.indent(
				Array.from(initialChunkIds, id => `${JSON.stringify(id)}: 1`).join(
					",\n"
				)
			),
			"};",
			"",
			withOnChunkLoad
				? `${
						RuntimeGlobals.onChunksLoaded
					}.require = ${runtimeTemplate.returningFunction(
						"installedChunks[chunkId]",
						"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("installedChunks[chunkIds[i]] = 1;"),
						withOnChunkLoad ? `${RuntimeGlobals.onChunksLoaded}();` : ""
					])};`
				: "// no chunk install function needed",
			"",
			withLoading
				? Template.asString([
						"// require() chunk loading for javascript",
						`${fn}.require = ${runtimeTemplate.basicFunction(
							"chunkId, promises",
							hasJsMatcher !== false
								? [
										'// "1" is the signal for "already loaded"',
										"if(!installedChunks[chunkId]) {",
										Template.indent([
											hasJsMatcher === true
												? "if(true) { // all chunks have JS"
												: `if(${hasJsMatcher("chunkId")}) {`,
											Template.indent([
												`installChunk(require(${JSON.stringify(
													rootOutputDir
												)} + ${
													RuntimeGlobals.getChunkScriptFilename
												}(chunkId)));`
											]),
											"} else installedChunks[chunkId] = 1;",
											""
										]),
										"}"
									]
								: "installedChunks[chunkId] = 1;"
						)};`
					])
				: "// 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([
							`var update = require(${JSON.stringify(rootOutputDir)} + ${
								RuntimeGlobals.getChunkUpdateScriptFilename
							}(chunkId));`,
							"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);"
						]),
						"}",
						"",
						Template.getFunctionContent(
							require("../hmr/JavascriptHotModuleReplacement.runtime.js")
						)
							.replace(/\$key\$/g, "require")
							.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 Promise.resolve().then(function() {",
							Template.indent([
								`return require(${JSON.stringify(rootOutputDir)} + ${
									RuntimeGlobals.getUpdateManifestFilename
								}());`
							]),
							"})['catch'](function(err) { if(err.code !== 'MODULE_NOT_FOUND') throw err; });"
						]),
						"}"
					])
				: "// no HMR manifest"
		]);
	}
}

module.exports = RequireChunkLoadingRuntimeModule;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const util = require("util");
const truncateArgs = require("../logging/truncateArgs");

/** @typedef {import("../logging/createConsoleLogger").LoggerConsole} LoggerConsole */

/**
 * @param {object} options options
 * @param {boolean=} options.colors colors
 * @param {boolean=} options.appendOnly append only
 * @param {NodeJS.WritableStream} options.stream stream
 * @returns {LoggerConsole} logger function
 */
module.exports = ({ colors, appendOnly, stream }) => {
	/** @type {string[] | undefined} */
	let currentStatusMessage = undefined;
	let hasStatusMessage = false;
	let currentIndent = "";
	let currentCollapsed = 0;

	/**
	 * @param {string} str string
	 * @param {string} prefix prefix
	 * @param {string} colorPrefix color prefix
	 * @param {string} colorSuffix color suffix
	 * @returns {string} indented string
	 */
	const indent = (str, prefix, colorPrefix, colorSuffix) => {
		if (str === "") return str;
		prefix = currentIndent + prefix;
		if (colors) {
			return (
				prefix +
				colorPrefix +
				str.replace(/\n/g, colorSuffix + "\n" + prefix + colorPrefix) +
				colorSuffix
			);
		} else {
			return prefix + str.replace(/\n/g, "\n" + prefix);
		}
	};

	const clearStatusMessage = () => {
		if (hasStatusMessage) {
			stream.write("\x1b[2K\r");
			hasStatusMessage = false;
		}
	};

	const writeStatusMessage = () => {
		if (!currentStatusMessage) return;
		const l = /** @type {TODO} */ (stream).columns || 40;
		const args = truncateArgs(currentStatusMessage, l - 1);
		const str = args.join(" ");
		const coloredStr = `\u001b[1m${str}\u001b[39m\u001b[22m`;
		stream.write(`\x1b[2K\r${coloredStr}`);
		hasStatusMessage = true;
	};

	/**
	 * @param {string} prefix prefix
	 * @param {string} colorPrefix color prefix
	 * @param {string} colorSuffix color suffix
	 * @returns {(function(...any[]): void)} function to write with colors
	 */
	const writeColored = (prefix, colorPrefix, colorSuffix) => {
		return (...args) => {
			if (currentCollapsed > 0) return;
			clearStatusMessage();
			const str = indent(
				util.format(...args),
				prefix,
				colorPrefix,
				colorSuffix
			);
			stream.write(str + "\n");
			writeStatusMessage();
		};
	};

	const writeGroupMessage = writeColored(
		"<-> ",
		"\u001b[1m\u001b[36m",
		"\u001b[39m\u001b[22m"
	);

	const writeGroupCollapsedMessage = writeColored(
		"<+> ",
		"\u001b[1m\u001b[36m",
		"\u001b[39m\u001b[22m"
	);

	return {
		log: writeColored("    ", "\u001b[1m", "\u001b[22m"),
		debug: writeColored("    ", "", ""),
		trace: writeColored("    ", "", ""),
		info: writeColored("<i> ", "\u001b[1m\u001b[32m", "\u001b[39m\u001b[22m"),
		warn: writeColored("<w> ", "\u001b[1m\u001b[33m", "\u001b[39m\u001b[22m"),
		error: writeColored("<e> ", "\u001b[1m\u001b[31m", "\u001b[39m\u001b[22m"),
		logTime: writeColored(
			"<t> ",
			"\u001b[1m\u001b[35m",
			"\u001b[39m\u001b[22m"
		),
		group: (...args) => {
			writeGroupMessage(...args);
			if (currentCollapsed > 0) {
				currentCollapsed++;
			} else {
				currentIndent += "  ";
			}
		},
		groupCollapsed: (...args) => {
			writeGroupCollapsedMessage(...args);
			currentCollapsed++;
		},
		groupEnd: () => {
			if (currentCollapsed > 0) currentCollapsed--;
			else if (currentIndent.length >= 2)
				currentIndent = currentIndent.slice(0, currentIndent.length - 2);
		},
		profile: console.profile && (name => console.profile(name)),
		profileEnd: console.profileEnd && (name => console.profileEnd(name)),
		clear:
			!appendOnly &&
			console.clear &&
			(() => {
				clearStatusMessage();
				console.clear();
				writeStatusMessage();
			}),
		status: appendOnly
			? writeColored("<s> ", "", "")
			: (name, ...args) => {
					args = args.filter(Boolean);
					if (name === undefined && args.length === 0) {
						clearStatusMessage();
						currentStatusMessage = undefined;
					} else if (
						typeof name === "string" &&
						name.startsWith("[webpack.Progress] ")
					) {
						currentStatusMessage = [name.slice(19), ...args];
						writeStatusMessage();
					} else if (name === "[webpack.Progress]") {
						currentStatusMessage = [...args];
						writeStatusMessage();
					} else {
						currentStatusMessage = [name, ...args];
						writeStatusMessage();
					}
				}
	};
};


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const { STAGE_ADVANCED } = require("../OptimizationStages");

/** @typedef {import("../Chunk")} Chunk */
/** @typedef {import("../Compiler")} Compiler */

/**
 * @typedef {object} AggressiveMergingPluginOptions
 * @property {number=} minSizeReduce minimal size reduction to trigger merging
 */

class AggressiveMergingPlugin {
	/**
	 * @param {AggressiveMergingPluginOptions=} [options] options object
	 */
	constructor(options) {
		if (
			(options !== undefined && typeof options !== "object") ||
			Array.isArray(options)
		) {
			throw new Error(
				"Argument should be an options object. To use defaults, pass in nothing.\nFor more info on options, see https://webpack.js.org/plugins/"
			);
		}
		this.options = options || {};
	}

	/**
	 * Apply the plugin
	 * @param {Compiler} compiler the compiler instance
	 * @returns {void}
	 */
	apply(compiler) {
		const options = this.options;
		const minSizeReduce = options.minSizeReduce || 1.5;

		compiler.hooks.thisCompilation.tap(
			"AggressiveMergingPlugin",
			compilation => {
				compilation.hooks.optimizeChunks.tap(
					{
						name: "AggressiveMergingPlugin",
						stage: STAGE_ADVANCED
					},
					chunks => {
						const chunkGraph = compilation.chunkGraph;
						/** @type {{a: Chunk, b: Chunk, improvement: number}[]} */
						let combinations = [];
						for (const a of chunks) {
							if (a.canBeInitial()) continue;
							for (const b of chunks) {
								if (b.canBeInitial()) continue;
								if (b === a) break;
								if (!chunkGraph.canChunksBeIntegrated(a, b)) {
									continue;
								}
								const aSize = chunkGraph.getChunkSize(b, {
									chunkOverhead: 0
								});
								const bSize = chunkGraph.getChunkSize(a, {
									chunkOverhead: 0
								});
								const abSize = chunkGraph.getIntegratedChunksSize(b, a, {
									chunkOverhead: 0
								});
								const improvement = (aSize + bSize) / abSize;
								combinations.push({
									a,
									b,
									improvement
								});
							}
						}

						combinations.sort((a, b) => {
							return b.improvement - a.improvement;
						});

						const pair = combinations[0];

						if (!pair) return;
						if (pair.improvement < minSizeReduce) return;

						chunkGraph.integrateChunks(pair.b, pair.a);
						compilation.chunks.delete(pair.a);
						return true;
					}
				);
			}
		);
	}
}

module.exports = AggressiveMergingPlugin;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const { STAGE_ADVANCED } = require("../OptimizationStages");
const { intersect } = require("../util/SetHelpers");
const {
	compareModulesByIdentifier,
	compareChunks
} = require("../util/comparators");
const createSchemaValidation = require("../util/create-schema-validation");
const identifierUtils = require("../util/identifier");

/** @typedef {import("../../declarations/plugins/optimize/AggressiveSplittingPlugin").AggressiveSplittingPluginOptions} AggressiveSplittingPluginOptions */
/** @typedef {import("../Chunk")} Chunk */
/** @typedef {import("../ChunkGraph")} ChunkGraph */
/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../Module")} Module */

const validate = createSchemaValidation(
	require("../../schemas/plugins/optimize/AggressiveSplittingPlugin.check.js"),
	() =>
		require("../../schemas/plugins/optimize/AggressiveSplittingPlugin.json"),
	{
		name: "Aggressive Splitting Plugin",
		baseDataPath: "options"
	}
);

/**
 * @param {ChunkGraph} chunkGraph the chunk graph
 * @param {Chunk} oldChunk the old chunk
 * @param {Chunk} newChunk the new chunk
 * @returns {(module: Module) => void} function to move module between chunks
 */
const moveModuleBetween = (chunkGraph, oldChunk, newChunk) => {
	return module => {
		chunkGraph.disconnectChunkAndModule(oldChunk, module);
		chunkGraph.connectChunkAndModule(newChunk, module);
	};
};

/**
 * @param {ChunkGraph} chunkGraph the chunk graph
 * @param {Chunk} chunk the chunk
 * @returns {function(Module): boolean} filter for entry module
 */
const isNotAEntryModule = (chunkGraph, chunk) => {
	return module => {
		return !chunkGraph.isEntryModuleInChunk(module, chunk);
	};
};

/** @type {WeakSet<Chunk>} */
const recordedChunks = new WeakSet();

class AggressiveSplittingPlugin {
	/**
	 * @param {AggressiveSplittingPluginOptions=} options options object
	 */
	constructor(options = {}) {
		validate(options);

		this.options = options;
		if (typeof this.options.minSize !== "number") {
			this.options.minSize = 30 * 1024;
		}
		if (typeof this.options.maxSize !== "number") {
			this.options.maxSize = 50 * 1024;
		}
		if (typeof this.options.chunkOverhead !== "number") {
			this.options.chunkOverhead = 0;
		}
		if (typeof this.options.entryChunkMultiplicator !== "number") {
			this.options.entryChunkMultiplicator = 1;
		}
	}

	/**
	 * @param {Chunk} chunk the chunk to test
	 * @returns {boolean} true if the chunk was recorded
	 */
	static wasChunkRecorded(chunk) {
		return recordedChunks.has(chunk);
	}

	/**
	 * Apply the plugin
	 * @param {Compiler} compiler the compiler instance
	 * @returns {void}
	 */
	apply(compiler) {
		compiler.hooks.thisCompilation.tap(
			"AggressiveSplittingPlugin",
			compilation => {
				let needAdditionalSeal = false;
				let newSplits;
				/** @type {Set<Chunk>} */
				let fromAggressiveSplittingSet;
				/** @type {Map<Chunk, TODO>} */
				let chunkSplitDataMap;
				compilation.hooks.optimize.tap("AggressiveSplittingPlugin", () => {
					newSplits = [];
					fromAggressiveSplittingSet = new Set();
					chunkSplitDataMap = new Map();
				});
				compilation.hooks.optimizeChunks.tap(
					{
						name: "AggressiveSplittingPlugin",
						stage: STAGE_ADVANCED
					},
					chunks => {
						const chunkGraph = compilation.chunkGraph;
						// Precompute stuff
						const nameToModuleMap = new Map();
						const moduleToNameMap = new Map();
						const makePathsRelative =
							identifierUtils.makePathsRelative.bindContextCache(
								compiler.context,
								compiler.root
							);
						for (const m of compilation.modules) {
							const name = makePathsRelative(m.identifier());
							nameToModuleMap.set(name, m);
							moduleToNameMap.set(m, name);
						}

						// Check used chunk ids
						const usedIds = new Set();
						for (const chunk of chunks) {
							usedIds.add(chunk.id);
						}

						const recordedSplits =
							(compilation.records && compilation.records.aggressiveSplits) ||
							[];
						const usedSplits = newSplits
							? recordedSplits.concat(newSplits)
							: recordedSplits;

						const minSize = /** @type {number} */ (this.options.minSize);
						const maxSize = /** @type {number} */ (this.options.maxSize);

						const applySplit = splitData => {
							// Cannot split if id is already taken
							if (splitData.id !== undefined && usedIds.has(splitData.id)) {
								return false;
							}

							// Get module objects from names
							const selectedModules = splitData.modules.map(name =>
								nameToModuleMap.get(name)
							);

							// Does the modules exist at all?
							if (!selectedModules.every(Boolean)) return false;

							// Check if size matches (faster than waiting for hash)
							let size = 0;
							for (const m of selectedModules) size += m.size();
							if (size !== splitData.size) return false;

							// get chunks with all modules
							const selectedChunks = intersect(
								selectedModules.map(
									m => new Set(chunkGraph.getModuleChunksIterable(m))
								)
							);

							// No relevant chunks found
							if (selectedChunks.size === 0) return false;

							// The found chunk is already the split or similar
							if (
								selectedChunks.size === 1 &&
								chunkGraph.getNumberOfChunkModules(
									Array.from(selectedChunks)[0]
								) === selectedModules.length
							) {
								const chunk = Array.from(selectedChunks)[0];
								if (fromAggressiveSplittingSet.has(chunk)) return false;
								fromAggressiveSplittingSet.add(chunk);
								chunkSplitDataMap.set(chunk, splitData);
								return true;
							}

							// split the chunk into two parts
							const newChunk = compilation.addChunk();
							newChunk.chunkReason = "aggressive splitted";
							for (const chunk of selectedChunks) {
								selectedModules.forEach(
									moveModuleBetween(chunkGraph, chunk, newChunk)
								);
								chunk.split(newChunk);
								chunk.name = null;
							}
							fromAggressiveSplittingSet.add(newChunk);
							chunkSplitDataMap.set(newChunk, splitData);

							if (splitData.id !== null && splitData.id !== undefined) {
								newChunk.id = splitData.id;
								newChunk.ids = [splitData.id];
							}
							return true;
						};

						// try to restore to recorded splitting
						let changed = false;
						for (let j = 0; j < usedSplits.length; j++) {
							const splitData = usedSplits[j];
							if (applySplit(splitData)) changed = true;
						}

						// for any chunk which isn't splitted yet, split it and create a new entry
						// start with the biggest chunk
						const cmpFn = compareChunks(chunkGraph);
						const sortedChunks = Array.from(chunks).sort((a, b) => {
							const diff1 =
								chunkGraph.getChunkModulesSize(b) -
								chunkGraph.getChunkModulesSize(a);
							if (diff1) return diff1;
							const diff2 =
								chunkGraph.getNumberOfChunkModules(a) -
								chunkGraph.getNumberOfChunkModules(b);
							if (diff2) return diff2;
							return cmpFn(a, b);
						});
						for (const chunk of sortedChunks) {
							if (fromAggressiveSplittingSet.has(chunk)) continue;
							const size = chunkGraph.getChunkModulesSize(chunk);
							if (
								size > maxSize &&
								chunkGraph.getNumberOfChunkModules(chunk) > 1
							) {
								const modules = chunkGraph
									.getOrderedChunkModules(chunk, compareModulesByIdentifier)
									.filter(isNotAEntryModule(chunkGraph, chunk));
								const selectedModules = [];
								let selectedModulesSize = 0;
								for (let k = 0; k < modules.length; k++) {
									const module = modules[k];
									const newSize = selectedModulesSize + module.size();
									if (newSize > maxSize && selectedModulesSize >= minSize) {
										break;
									}
									selectedModulesSize = newSize;
									selectedModules.push(module);
								}
								if (selectedModules.length === 0) continue;
								const splitData = {
									modules: selectedModules
										.map(m => moduleToNameMap.get(m))
										.sort(),
									size: selectedModulesSize
								};

								if (applySplit(splitData)) {
									newSplits = (newSplits || []).concat(splitData);
									changed = true;
								}
							}
						}
						if (changed) return true;
					}
				);
				compilation.hooks.recordHash.tap(
					"AggressiveSplittingPlugin",
					records => {
						// 4. save made splittings to records
						const allSplits = new Set();
						const invalidSplits = new Set();

						// Check if some splittings are invalid
						// We remove invalid splittings and try again
						for (const chunk of compilation.chunks) {
							const splitData = chunkSplitDataMap.get(chunk);
							if (splitData !== undefined) {
								if (splitData.hash && chunk.hash !== splitData.hash) {
									// Split was successful, but hash doesn't equal
									// We can throw away the split since it's useless now
									invalidSplits.add(splitData);
								}
							}
						}

						if (invalidSplits.size > 0) {
							records.aggressiveSplits = records.aggressiveSplits.filter(
								splitData => !invalidSplits.has(splitData)
							);
							needAdditionalSeal = true;
						} else {
							// set hash and id values on all (new) splittings
							for (const chunk of compilation.chunks) {
								const splitData = chunkSplitDataMap.get(chunk);
								if (splitData !== undefined) {
									splitData.hash = chunk.hash;
									splitData.id = chunk.id;
									allSplits.add(splitData);
									// set flag for stats
									recordedChunks.add(chunk);
								}
							}

							// Also add all unused historical splits (after the used ones)
							// They can still be used in some future compilation
							const recordedSplits =
								compilation.records && compilation.records.aggressiveSplits;
							if (recordedSplits) {
								for (const splitData of recordedSplits) {
									if (!invalidSplits.has(splitData)) allSplits.add(splitData);
								}
							}

							// record all splits
							records.aggressiveSplits = Array.from(allSplits);

							needAdditionalSeal = false;
						}
					}
				);
				compilation.hooks.needAdditionalSeal.tap(
					"AggressiveSplittingPlugin",
					() => {
						if (needAdditionalSeal) {
							needAdditionalSeal = false;
							return true;
						}
					}
				);
			}
		);
	}
}
module.exports = AggressiveSplittingPlugin;