You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
	
	
		
			670 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			JavaScript
		
	
		
		
			
		
	
	
			670 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			JavaScript
		
	
| 
											9 months ago
										 | /* | ||
|  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | ||
|  | 	Author Tobias Koppers @sokra | ||
|  | */ | ||
|  | 
 | ||
|  | "use strict"; | ||
|  | 
 | ||
|  | const Compiler = require("./Compiler"); | ||
|  | const MultiCompiler = require("./MultiCompiler"); | ||
|  | const NormalModule = require("./NormalModule"); | ||
|  | const createSchemaValidation = require("./util/create-schema-validation"); | ||
|  | const { contextify } = require("./util/identifier"); | ||
|  | 
 | ||
|  | /** @typedef {import("tapable").Tap} Tap */ | ||
|  | /** @typedef {import("../declarations/plugins/ProgressPlugin").HandlerFunction} HandlerFunction */ | ||
|  | /** @typedef {import("../declarations/plugins/ProgressPlugin").ProgressPluginArgument} ProgressPluginArgument */ | ||
|  | /** @typedef {import("../declarations/plugins/ProgressPlugin").ProgressPluginOptions} ProgressPluginOptions */ | ||
|  | /** @typedef {import("./Dependency")} Dependency */ | ||
|  | /** @typedef {import("./Entrypoint").EntryOptions} EntryOptions */ | ||
|  | /** @typedef {import("./Module")} Module */ | ||
|  | /** @typedef {import("./logging/Logger").Logger} Logger */ | ||
|  | 
 | ||
|  | /** | ||
|  |  * @typedef {Object} CountsData | ||
|  |  * @property {number} modulesCount modules count | ||
|  |  * @property {number} dependenciesCount dependencies count | ||
|  |  */ | ||
|  | 
 | ||
|  | const validate = createSchemaValidation( | ||
|  | 	require("../schemas/plugins/ProgressPlugin.check.js"), | ||
|  | 	() => require("../schemas/plugins/ProgressPlugin.json"), | ||
|  | 	{ | ||
|  | 		name: "Progress Plugin", | ||
|  | 		baseDataPath: "options" | ||
|  | 	} | ||
|  | ); | ||
|  | 
 | ||
|  | /** | ||
|  |  * @param {number} a a | ||
|  |  * @param {number} b b | ||
|  |  * @param {number} c c | ||
|  |  * @returns {number} median | ||
|  |  */ | ||
|  | const median3 = (a, b, c) => { | ||
|  | 	return a + b + c - Math.max(a, b, c) - Math.min(a, b, c); | ||
|  | }; | ||
|  | 
 | ||
|  | /** | ||
|  |  * @param {boolean | null | undefined} profile need profile | ||
|  |  * @param {Logger} logger logger | ||
|  |  * @returns {defaultHandler} default handler | ||
|  |  */ | ||
|  | const createDefaultHandler = (profile, logger) => { | ||
|  | 	/** @type {{ value: string | undefined, time: number }[]} */ | ||
|  | 	const lastStateInfo = []; | ||
|  | 
 | ||
|  | 	/** | ||
|  | 	 * @param {number} percentage percentage | ||
|  | 	 * @param {string} msg message | ||
|  | 	 * @param {...string} args additional arguments | ||
|  | 	 */ | ||
|  | 	const defaultHandler = (percentage, msg, ...args) => { | ||
|  | 		if (profile) { | ||
|  | 			if (percentage === 0) { | ||
|  | 				lastStateInfo.length = 0; | ||
|  | 			} | ||
|  | 			const fullState = [msg, ...args]; | ||
|  | 			const state = fullState.map(s => s.replace(/\d+\/\d+ /g, "")); | ||
|  | 			const now = Date.now(); | ||
|  | 			const len = Math.max(state.length, lastStateInfo.length); | ||
|  | 			for (let i = len; i >= 0; i--) { | ||
|  | 				const stateItem = i < state.length ? state[i] : undefined; | ||
|  | 				const lastStateItem = | ||
|  | 					i < lastStateInfo.length ? lastStateInfo[i] : undefined; | ||
|  | 				if (lastStateItem) { | ||
|  | 					if (stateItem !== lastStateItem.value) { | ||
|  | 						const diff = now - lastStateItem.time; | ||
|  | 						if (lastStateItem.value) { | ||
|  | 							let reportState = lastStateItem.value; | ||
|  | 							if (i > 0) { | ||
|  | 								reportState = lastStateInfo[i - 1].value + " > " + reportState; | ||
|  | 							} | ||
|  | 							const stateMsg = `${" | ".repeat(i)}${diff} ms ${reportState}`; | ||
|  | 							const d = diff; | ||
|  | 							// This depends on timing so we ignore it for coverage
 | ||
|  | 							/* istanbul ignore next */ | ||
|  | 							{ | ||
|  | 								if (d > 10000) { | ||
|  | 									logger.error(stateMsg); | ||
|  | 								} else if (d > 1000) { | ||
|  | 									logger.warn(stateMsg); | ||
|  | 								} else if (d > 10) { | ||
|  | 									logger.info(stateMsg); | ||
|  | 								} else if (d > 5) { | ||
|  | 									logger.log(stateMsg); | ||
|  | 								} else { | ||
|  | 									logger.debug(stateMsg); | ||
|  | 								} | ||
|  | 							} | ||
|  | 						} | ||
|  | 						if (stateItem === undefined) { | ||
|  | 							lastStateInfo.length = i; | ||
|  | 						} else { | ||
|  | 							lastStateItem.value = stateItem; | ||
|  | 							lastStateItem.time = now; | ||
|  | 							lastStateInfo.length = i + 1; | ||
|  | 						} | ||
|  | 					} | ||
|  | 				} else { | ||
|  | 					lastStateInfo[i] = { | ||
|  | 						value: stateItem, | ||
|  | 						time: now | ||
|  | 					}; | ||
|  | 				} | ||
|  | 			} | ||
|  | 		} | ||
|  | 		logger.status(`${Math.floor(percentage * 100)}%`, msg, ...args); | ||
|  | 		if (percentage === 1 || (!msg && args.length === 0)) logger.status(); | ||
|  | 	}; | ||
|  | 
 | ||
|  | 	return defaultHandler; | ||
|  | }; | ||
|  | 
 | ||
|  | /** | ||
|  |  * @callback ReportProgress | ||
|  |  * @param {number} p percentage | ||
|  |  * @param {...string} args additional arguments | ||
|  |  * @returns {void} | ||
|  |  */ | ||
|  | 
 | ||
|  | /** @type {WeakMap<Compiler, ReportProgress | undefined>} */ | ||
|  | const progressReporters = new WeakMap(); | ||
|  | 
 | ||
|  | class ProgressPlugin { | ||
|  | 	/** | ||
|  | 	 * @param {Compiler} compiler the current compiler | ||
|  | 	 * @returns {ReportProgress | undefined} a progress reporter, if any | ||
|  | 	 */ | ||
|  | 	static getReporter(compiler) { | ||
|  | 		return progressReporters.get(compiler); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 	 * @param {ProgressPluginArgument} options options | ||
|  | 	 */ | ||
|  | 	constructor(options = {}) { | ||
|  | 		if (typeof options === "function") { | ||
|  | 			options = { | ||
|  | 				handler: options | ||
|  | 			}; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		validate(options); | ||
|  | 		options = { ...ProgressPlugin.defaultOptions, ...options }; | ||
|  | 
 | ||
|  | 		this.profile = options.profile; | ||
|  | 		this.handler = options.handler; | ||
|  | 		this.modulesCount = options.modulesCount; | ||
|  | 		this.dependenciesCount = options.dependenciesCount; | ||
|  | 		this.showEntries = options.entries; | ||
|  | 		this.showModules = options.modules; | ||
|  | 		this.showDependencies = options.dependencies; | ||
|  | 		this.showActiveModules = options.activeModules; | ||
|  | 		this.percentBy = options.percentBy; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 	 * @param {Compiler | MultiCompiler} compiler webpack compiler | ||
|  | 	 * @returns {void} | ||
|  | 	 */ | ||
|  | 	apply(compiler) { | ||
|  | 		const handler = | ||
|  | 			this.handler || | ||
|  | 			createDefaultHandler( | ||
|  | 				this.profile, | ||
|  | 				compiler.getInfrastructureLogger("webpack.Progress") | ||
|  | 			); | ||
|  | 		if (compiler instanceof MultiCompiler) { | ||
|  | 			this._applyOnMultiCompiler(compiler, handler); | ||
|  | 		} else if (compiler instanceof Compiler) { | ||
|  | 			this._applyOnCompiler(compiler, handler); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 	 * @param {MultiCompiler} compiler webpack multi-compiler | ||
|  | 	 * @param {HandlerFunction} handler function that executes for every progress step | ||
|  | 	 * @returns {void} | ||
|  | 	 */ | ||
|  | 	_applyOnMultiCompiler(compiler, handler) { | ||
|  | 		const states = compiler.compilers.map( | ||
|  | 			() => /** @type {[number, ...string[]]} */ ([0]) | ||
|  | 		); | ||
|  | 		compiler.compilers.forEach((compiler, idx) => { | ||
|  | 			new ProgressPlugin((p, msg, ...args) => { | ||
|  | 				states[idx] = [p, msg, ...args]; | ||
|  | 				let sum = 0; | ||
|  | 				for (const [p] of states) sum += p; | ||
|  | 				handler(sum / states.length, `[${idx}] ${msg}`, ...args); | ||
|  | 			}).apply(compiler); | ||
|  | 		}); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 	 * @param {Compiler} compiler webpack compiler | ||
|  | 	 * @param {HandlerFunction} handler function that executes for every progress step | ||
|  | 	 * @returns {void} | ||
|  | 	 */ | ||
|  | 	_applyOnCompiler(compiler, handler) { | ||
|  | 		const showEntries = this.showEntries; | ||
|  | 		const showModules = this.showModules; | ||
|  | 		const showDependencies = this.showDependencies; | ||
|  | 		const showActiveModules = this.showActiveModules; | ||
|  | 		let lastActiveModule = ""; | ||
|  | 		let currentLoader = ""; | ||
|  | 		let lastModulesCount = 0; | ||
|  | 		let lastDependenciesCount = 0; | ||
|  | 		let lastEntriesCount = 0; | ||
|  | 		let modulesCount = 0; | ||
|  | 		let dependenciesCount = 0; | ||
|  | 		let entriesCount = 1; | ||
|  | 		let doneModules = 0; | ||
|  | 		let doneDependencies = 0; | ||
|  | 		let doneEntries = 0; | ||
|  | 		const activeModules = new Set(); | ||
|  | 		let lastUpdate = 0; | ||
|  | 
 | ||
|  | 		const updateThrottled = () => { | ||
|  | 			if (lastUpdate + 500 < Date.now()) update(); | ||
|  | 		}; | ||
|  | 
 | ||
|  | 		const update = () => { | ||
|  | 			/** @type {string[]} */ | ||
|  | 			const items = []; | ||
|  | 			const percentByModules = | ||
|  | 				doneModules / | ||
|  | 				Math.max(lastModulesCount || this.modulesCount || 1, modulesCount); | ||
|  | 			const percentByEntries = | ||
|  | 				doneEntries / | ||
|  | 				Math.max(lastEntriesCount || this.dependenciesCount || 1, entriesCount); | ||
|  | 			const percentByDependencies = | ||
|  | 				doneDependencies / | ||
|  | 				Math.max(lastDependenciesCount || 1, dependenciesCount); | ||
|  | 			let percentageFactor; | ||
|  | 
 | ||
|  | 			switch (this.percentBy) { | ||
|  | 				case "entries": | ||
|  | 					percentageFactor = percentByEntries; | ||
|  | 					break; | ||
|  | 				case "dependencies": | ||
|  | 					percentageFactor = percentByDependencies; | ||
|  | 					break; | ||
|  | 				case "modules": | ||
|  | 					percentageFactor = percentByModules; | ||
|  | 					break; | ||
|  | 				default: | ||
|  | 					percentageFactor = median3( | ||
|  | 						percentByModules, | ||
|  | 						percentByEntries, | ||
|  | 						percentByDependencies | ||
|  | 					); | ||
|  | 			} | ||
|  | 
 | ||
|  | 			const percentage = 0.1 + percentageFactor * 0.55; | ||
|  | 
 | ||
|  | 			if (currentLoader) { | ||
|  | 				items.push( | ||
|  | 					`import loader ${contextify( | ||
|  | 						compiler.context, | ||
|  | 						currentLoader, | ||
|  | 						compiler.root | ||
|  | 					)}`
 | ||
|  | 				); | ||
|  | 			} else { | ||
|  | 				const statItems = []; | ||
|  | 				if (showEntries) { | ||
|  | 					statItems.push(`${doneEntries}/${entriesCount} entries`); | ||
|  | 				} | ||
|  | 				if (showDependencies) { | ||
|  | 					statItems.push( | ||
|  | 						`${doneDependencies}/${dependenciesCount} dependencies` | ||
|  | 					); | ||
|  | 				} | ||
|  | 				if (showModules) { | ||
|  | 					statItems.push(`${doneModules}/${modulesCount} modules`); | ||
|  | 				} | ||
|  | 				if (showActiveModules) { | ||
|  | 					statItems.push(`${activeModules.size} active`); | ||
|  | 				} | ||
|  | 				if (statItems.length > 0) { | ||
|  | 					items.push(statItems.join(" ")); | ||
|  | 				} | ||
|  | 				if (showActiveModules) { | ||
|  | 					items.push(lastActiveModule); | ||
|  | 				} | ||
|  | 			} | ||
|  | 			handler(percentage, "building", ...items); | ||
|  | 			lastUpdate = Date.now(); | ||
|  | 		}; | ||
|  | 
 | ||
|  | 		const factorizeAdd = () => { | ||
|  | 			dependenciesCount++; | ||
|  | 			if (dependenciesCount < 50 || dependenciesCount % 100 === 0) | ||
|  | 				updateThrottled(); | ||
|  | 		}; | ||
|  | 
 | ||
|  | 		const factorizeDone = () => { | ||
|  | 			doneDependencies++; | ||
|  | 			if (doneDependencies < 50 || doneDependencies % 100 === 0) | ||
|  | 				updateThrottled(); | ||
|  | 		}; | ||
|  | 
 | ||
|  | 		const moduleAdd = () => { | ||
|  | 			modulesCount++; | ||
|  | 			if (modulesCount < 50 || modulesCount % 100 === 0) updateThrottled(); | ||
|  | 		}; | ||
|  | 
 | ||
|  | 		// only used when showActiveModules is set
 | ||
|  | 		/** | ||
|  | 		 * @param {Module} module the module | ||
|  | 		 */ | ||
|  | 		const moduleBuild = module => { | ||
|  | 			const ident = module.identifier(); | ||
|  | 			if (ident) { | ||
|  | 				activeModules.add(ident); | ||
|  | 				lastActiveModule = ident; | ||
|  | 				update(); | ||
|  | 			} | ||
|  | 		}; | ||
|  | 
 | ||
|  | 		/** | ||
|  | 		 * @param {Dependency} entry entry dependency | ||
|  | 		 * @param {EntryOptions} options options object | ||
|  | 		 */ | ||
|  | 		const entryAdd = (entry, options) => { | ||
|  | 			entriesCount++; | ||
|  | 			if (entriesCount < 5 || entriesCount % 10 === 0) updateThrottled(); | ||
|  | 		}; | ||
|  | 
 | ||
|  | 		/** | ||
|  | 		 * @param {Module} module the module | ||
|  | 		 */ | ||
|  | 		const moduleDone = module => { | ||
|  | 			doneModules++; | ||
|  | 			if (showActiveModules) { | ||
|  | 				const ident = module.identifier(); | ||
|  | 				if (ident) { | ||
|  | 					activeModules.delete(ident); | ||
|  | 					if (lastActiveModule === ident) { | ||
|  | 						lastActiveModule = ""; | ||
|  | 						for (const m of activeModules) { | ||
|  | 							lastActiveModule = m; | ||
|  | 						} | ||
|  | 						update(); | ||
|  | 						return; | ||
|  | 					} | ||
|  | 				} | ||
|  | 			} | ||
|  | 			if (doneModules < 50 || doneModules % 100 === 0) updateThrottled(); | ||
|  | 		}; | ||
|  | 
 | ||
|  | 		/** | ||
|  | 		 * @param {Dependency} entry entry dependency | ||
|  | 		 * @param {EntryOptions} options options object | ||
|  | 		 */ | ||
|  | 		const entryDone = (entry, options) => { | ||
|  | 			doneEntries++; | ||
|  | 			update(); | ||
|  | 		}; | ||
|  | 
 | ||
|  | 		const cache = compiler | ||
|  | 			.getCache("ProgressPlugin") | ||
|  | 			.getItemCache("counts", null); | ||
|  | 
 | ||
|  | 		/** @type {Promise<CountsData> | undefined} */ | ||
|  | 		let cacheGetPromise; | ||
|  | 
 | ||
|  | 		compiler.hooks.beforeCompile.tap("ProgressPlugin", () => { | ||
|  | 			if (!cacheGetPromise) { | ||
|  | 				cacheGetPromise = cache.getPromise().then( | ||
|  | 					data => { | ||
|  | 						if (data) { | ||
|  | 							lastModulesCount = lastModulesCount || data.modulesCount; | ||
|  | 							lastDependenciesCount = | ||
|  | 								lastDependenciesCount || data.dependenciesCount; | ||
|  | 						} | ||
|  | 						return data; | ||
|  | 					}, | ||
|  | 					err => { | ||
|  | 						// Ignore error
 | ||
|  | 					} | ||
|  | 				); | ||
|  | 			} | ||
|  | 		}); | ||
|  | 
 | ||
|  | 		compiler.hooks.afterCompile.tapPromise("ProgressPlugin", compilation => { | ||
|  | 			if (compilation.compiler.isChild()) return Promise.resolve(); | ||
|  | 			return /** @type {Promise<CountsData>} */ (cacheGetPromise).then( | ||
|  | 				async oldData => { | ||
|  | 					if ( | ||
|  | 						!oldData || | ||
|  | 						oldData.modulesCount !== modulesCount || | ||
|  | 						oldData.dependenciesCount !== dependenciesCount | ||
|  | 					) { | ||
|  | 						await cache.storePromise({ modulesCount, dependenciesCount }); | ||
|  | 					} | ||
|  | 				} | ||
|  | 			); | ||
|  | 		}); | ||
|  | 
 | ||
|  | 		compiler.hooks.compilation.tap("ProgressPlugin", compilation => { | ||
|  | 			if (compilation.compiler.isChild()) return; | ||
|  | 			lastModulesCount = modulesCount; | ||
|  | 			lastEntriesCount = entriesCount; | ||
|  | 			lastDependenciesCount = dependenciesCount; | ||
|  | 			modulesCount = dependenciesCount = entriesCount = 0; | ||
|  | 			doneModules = doneDependencies = doneEntries = 0; | ||
|  | 
 | ||
|  | 			compilation.factorizeQueue.hooks.added.tap( | ||
|  | 				"ProgressPlugin", | ||
|  | 				factorizeAdd | ||
|  | 			); | ||
|  | 			compilation.factorizeQueue.hooks.result.tap( | ||
|  | 				"ProgressPlugin", | ||
|  | 				factorizeDone | ||
|  | 			); | ||
|  | 
 | ||
|  | 			compilation.addModuleQueue.hooks.added.tap("ProgressPlugin", moduleAdd); | ||
|  | 			compilation.processDependenciesQueue.hooks.result.tap( | ||
|  | 				"ProgressPlugin", | ||
|  | 				moduleDone | ||
|  | 			); | ||
|  | 
 | ||
|  | 			if (showActiveModules) { | ||
|  | 				compilation.hooks.buildModule.tap("ProgressPlugin", moduleBuild); | ||
|  | 			} | ||
|  | 
 | ||
|  | 			compilation.hooks.addEntry.tap("ProgressPlugin", entryAdd); | ||
|  | 			compilation.hooks.failedEntry.tap("ProgressPlugin", entryDone); | ||
|  | 			compilation.hooks.succeedEntry.tap("ProgressPlugin", entryDone); | ||
|  | 
 | ||
|  | 			// avoid dynamic require if bundled with webpack
 | ||
|  | 			// @ts-expect-error
 | ||
|  | 			if (typeof __webpack_require__ !== "function") { | ||
|  | 				const requiredLoaders = new Set(); | ||
|  | 				NormalModule.getCompilationHooks(compilation).beforeLoaders.tap( | ||
|  | 					"ProgressPlugin", | ||
|  | 					loaders => { | ||
|  | 						for (const loader of loaders) { | ||
|  | 							if ( | ||
|  | 								loader.type !== "module" && | ||
|  | 								!requiredLoaders.has(loader.loader) | ||
|  | 							) { | ||
|  | 								requiredLoaders.add(loader.loader); | ||
|  | 								currentLoader = loader.loader; | ||
|  | 								update(); | ||
|  | 								require(loader.loader); | ||
|  | 							} | ||
|  | 						} | ||
|  | 						if (currentLoader) { | ||
|  | 							currentLoader = ""; | ||
|  | 							update(); | ||
|  | 						} | ||
|  | 					} | ||
|  | 				); | ||
|  | 			} | ||
|  | 
 | ||
|  | 			const hooks = { | ||
|  | 				finishModules: "finish module graph", | ||
|  | 				seal: "plugins", | ||
|  | 				optimizeDependencies: "dependencies optimization", | ||
|  | 				afterOptimizeDependencies: "after dependencies optimization", | ||
|  | 				beforeChunks: "chunk graph", | ||
|  | 				afterChunks: "after chunk graph", | ||
|  | 				optimize: "optimizing", | ||
|  | 				optimizeModules: "module optimization", | ||
|  | 				afterOptimizeModules: "after module optimization", | ||
|  | 				optimizeChunks: "chunk optimization", | ||
|  | 				afterOptimizeChunks: "after chunk optimization", | ||
|  | 				optimizeTree: "module and chunk tree optimization", | ||
|  | 				afterOptimizeTree: "after module and chunk tree optimization", | ||
|  | 				optimizeChunkModules: "chunk modules optimization", | ||
|  | 				afterOptimizeChunkModules: "after chunk modules optimization", | ||
|  | 				reviveModules: "module reviving", | ||
|  | 				beforeModuleIds: "before module ids", | ||
|  | 				moduleIds: "module ids", | ||
|  | 				optimizeModuleIds: "module id optimization", | ||
|  | 				afterOptimizeModuleIds: "module id optimization", | ||
|  | 				reviveChunks: "chunk reviving", | ||
|  | 				beforeChunkIds: "before chunk ids", | ||
|  | 				chunkIds: "chunk ids", | ||
|  | 				optimizeChunkIds: "chunk id optimization", | ||
|  | 				afterOptimizeChunkIds: "after chunk id optimization", | ||
|  | 				recordModules: "record modules", | ||
|  | 				recordChunks: "record chunks", | ||
|  | 				beforeModuleHash: "module hashing", | ||
|  | 				beforeCodeGeneration: "code generation", | ||
|  | 				beforeRuntimeRequirements: "runtime requirements", | ||
|  | 				beforeHash: "hashing", | ||
|  | 				afterHash: "after hashing", | ||
|  | 				recordHash: "record hash", | ||
|  | 				beforeModuleAssets: "module assets processing", | ||
|  | 				beforeChunkAssets: "chunk assets processing", | ||
|  | 				processAssets: "asset processing", | ||
|  | 				afterProcessAssets: "after asset optimization", | ||
|  | 				record: "recording", | ||
|  | 				afterSeal: "after seal" | ||
|  | 			}; | ||
|  | 			const numberOfHooks = Object.keys(hooks).length; | ||
|  | 			Object.keys(hooks).forEach((name, idx) => { | ||
|  | 				const title = hooks[/** @type {keyof typeof hooks} */ (name)]; | ||
|  | 				const percentage = (idx / numberOfHooks) * 0.25 + 0.7; | ||
|  | 				compilation.hooks[/** @type {keyof typeof hooks} */ (name)].intercept({ | ||
|  | 					name: "ProgressPlugin", | ||
|  | 					call() { | ||
|  | 						handler(percentage, "sealing", title); | ||
|  | 					}, | ||
|  | 					done() { | ||
|  | 						progressReporters.set(compiler, undefined); | ||
|  | 						handler(percentage, "sealing", title); | ||
|  | 					}, | ||
|  | 					result() { | ||
|  | 						handler(percentage, "sealing", title); | ||
|  | 					}, | ||
|  | 					error() { | ||
|  | 						handler(percentage, "sealing", title); | ||
|  | 					}, | ||
|  | 					tap(tap) { | ||
|  | 						// p is percentage from 0 to 1
 | ||
|  | 						// args is any number of messages in a hierarchical matter
 | ||
|  | 						progressReporters.set(compilation.compiler, (p, ...args) => { | ||
|  | 							handler(percentage, "sealing", title, tap.name, ...args); | ||
|  | 						}); | ||
|  | 						handler(percentage, "sealing", title, tap.name); | ||
|  | 					} | ||
|  | 				}); | ||
|  | 			}); | ||
|  | 		}); | ||
|  | 		compiler.hooks.make.intercept({ | ||
|  | 			name: "ProgressPlugin", | ||
|  | 			call() { | ||
|  | 				handler(0.1, "building"); | ||
|  | 			}, | ||
|  | 			done() { | ||
|  | 				handler(0.65, "building"); | ||
|  | 			} | ||
|  | 		}); | ||
|  | 		/** | ||
|  | 		 * @param {TODO} hook hook | ||
|  | 		 * @param {number} progress progress from 0 to 1 | ||
|  | 		 * @param {string} category category | ||
|  | 		 * @param {string} name name | ||
|  | 		 */ | ||
|  | 		const interceptHook = (hook, progress, category, name) => { | ||
|  | 			hook.intercept({ | ||
|  | 				name: "ProgressPlugin", | ||
|  | 				call() { | ||
|  | 					handler(progress, category, name); | ||
|  | 				}, | ||
|  | 				done() { | ||
|  | 					progressReporters.set(compiler, undefined); | ||
|  | 					handler(progress, category, name); | ||
|  | 				}, | ||
|  | 				result() { | ||
|  | 					handler(progress, category, name); | ||
|  | 				}, | ||
|  | 				error() { | ||
|  | 					handler(progress, category, name); | ||
|  | 				}, | ||
|  | 				/** | ||
|  | 				 * @param {Tap} tap tap | ||
|  | 				 */ | ||
|  | 				tap(tap) { | ||
|  | 					progressReporters.set(compiler, (p, ...args) => { | ||
|  | 						handler(progress, category, name, tap.name, ...args); | ||
|  | 					}); | ||
|  | 					handler(progress, category, name, tap.name); | ||
|  | 				} | ||
|  | 			}); | ||
|  | 		}; | ||
|  | 		compiler.cache.hooks.endIdle.intercept({ | ||
|  | 			name: "ProgressPlugin", | ||
|  | 			call() { | ||
|  | 				handler(0, ""); | ||
|  | 			} | ||
|  | 		}); | ||
|  | 		interceptHook(compiler.cache.hooks.endIdle, 0.01, "cache", "end idle"); | ||
|  | 		compiler.hooks.beforeRun.intercept({ | ||
|  | 			name: "ProgressPlugin", | ||
|  | 			call() { | ||
|  | 				handler(0, ""); | ||
|  | 			} | ||
|  | 		}); | ||
|  | 		interceptHook(compiler.hooks.beforeRun, 0.01, "setup", "before run"); | ||
|  | 		interceptHook(compiler.hooks.run, 0.02, "setup", "run"); | ||
|  | 		interceptHook(compiler.hooks.watchRun, 0.03, "setup", "watch run"); | ||
|  | 		interceptHook( | ||
|  | 			compiler.hooks.normalModuleFactory, | ||
|  | 			0.04, | ||
|  | 			"setup", | ||
|  | 			"normal module factory" | ||
|  | 		); | ||
|  | 		interceptHook( | ||
|  | 			compiler.hooks.contextModuleFactory, | ||
|  | 			0.05, | ||
|  | 			"setup", | ||
|  | 			"context module factory" | ||
|  | 		); | ||
|  | 		interceptHook( | ||
|  | 			compiler.hooks.beforeCompile, | ||
|  | 			0.06, | ||
|  | 			"setup", | ||
|  | 			"before compile" | ||
|  | 		); | ||
|  | 		interceptHook(compiler.hooks.compile, 0.07, "setup", "compile"); | ||
|  | 		interceptHook(compiler.hooks.thisCompilation, 0.08, "setup", "compilation"); | ||
|  | 		interceptHook(compiler.hooks.compilation, 0.09, "setup", "compilation"); | ||
|  | 		interceptHook(compiler.hooks.finishMake, 0.69, "building", "finish"); | ||
|  | 		interceptHook(compiler.hooks.emit, 0.95, "emitting", "emit"); | ||
|  | 		interceptHook(compiler.hooks.afterEmit, 0.98, "emitting", "after emit"); | ||
|  | 		interceptHook(compiler.hooks.done, 0.99, "done", "plugins"); | ||
|  | 		compiler.hooks.done.intercept({ | ||
|  | 			name: "ProgressPlugin", | ||
|  | 			done() { | ||
|  | 				handler(0.99, ""); | ||
|  | 			} | ||
|  | 		}); | ||
|  | 		interceptHook( | ||
|  | 			compiler.cache.hooks.storeBuildDependencies, | ||
|  | 			0.99, | ||
|  | 			"cache", | ||
|  | 			"store build dependencies" | ||
|  | 		); | ||
|  | 		interceptHook(compiler.cache.hooks.shutdown, 0.99, "cache", "shutdown"); | ||
|  | 		interceptHook(compiler.cache.hooks.beginIdle, 0.99, "cache", "begin idle"); | ||
|  | 		interceptHook( | ||
|  | 			compiler.hooks.watchClose, | ||
|  | 			0.99, | ||
|  | 			"end", | ||
|  | 			"closing watch compilation" | ||
|  | 		); | ||
|  | 		compiler.cache.hooks.beginIdle.intercept({ | ||
|  | 			name: "ProgressPlugin", | ||
|  | 			done() { | ||
|  | 				handler(1, ""); | ||
|  | 			} | ||
|  | 		}); | ||
|  | 		compiler.cache.hooks.shutdown.intercept({ | ||
|  | 			name: "ProgressPlugin", | ||
|  | 			done() { | ||
|  | 				handler(1, ""); | ||
|  | 			} | ||
|  | 		}); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | ProgressPlugin.defaultOptions = { | ||
|  | 	profile: false, | ||
|  | 	modulesCount: 5000, | ||
|  | 	dependenciesCount: 10000, | ||
|  | 	modules: true, | ||
|  | 	dependencies: true, | ||
|  | 	activeModules: false, | ||
|  | 	entries: true | ||
|  | }; | ||
|  | 
 | ||
|  | ProgressPlugin.createDefaultHandler = createDefaultHandler; | ||
|  | 
 | ||
|  | module.exports = ProgressPlugin; |