| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | 	Author Tobias Koppers @sokra | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | "use strict"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-13 04:59:09 +08:00
										 |  |  | const FileSystemInfo = require("../FileSystemInfo"); | 
					
						
							| 
									
										
										
										
											2020-08-14 13:27:30 +08:00
										 |  |  | const ProgressPlugin = require("../ProgressPlugin"); | 
					
						
							| 
									
										
										
										
											2020-08-24 18:54:22 +08:00
										 |  |  | const { formatSize } = require("../SizeFormatHelpers"); | 
					
						
							| 
									
										
										
										
											2019-08-14 00:59:17 +08:00
										 |  |  | const LazySet = require("../util/LazySet"); | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | const makeSerializable = require("../util/makeSerializable"); | 
					
						
							| 
									
										
										
										
											2020-12-27 05:32:57 +08:00
										 |  |  | const memoize = require("../util/memoize"); | 
					
						
							| 
									
										
										
										
											2021-01-21 23:32:49 +08:00
										 |  |  | const { | 
					
						
							|  |  |  | 	createFileSerializer, | 
					
						
							|  |  |  | 	NOT_SERIALIZABLE | 
					
						
							|  |  |  | } = require("../util/serialization"); | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-26 06:36:16 +08:00
										 |  |  | /** @typedef {import("../../declarations/WebpackOptions").SnapshotOptions} SnapshotOptions */ | 
					
						
							| 
									
										
										
										
											2019-11-12 20:55:13 +08:00
										 |  |  | /** @typedef {import("../Cache").Etag} Etag */ | 
					
						
							| 
									
										
										
										
											2020-08-14 13:27:30 +08:00
										 |  |  | /** @typedef {import("../Compiler")} Compiler */ | 
					
						
							| 
									
										
										
										
											2020-08-23 03:54:34 +08:00
										 |  |  | /** @typedef {import("../FileSystemInfo").Snapshot} Snapshot */ | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | /** @typedef {import("../logging/Logger").Logger} Logger */ | 
					
						
							|  |  |  | /** @typedef {import("../util/fs").IntermediateFileSystem} IntermediateFileSystem */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-20 18:31:36 +08:00
										 |  |  | class PackContainer { | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {Object} data stored data | 
					
						
							|  |  |  | 	 * @param {string} version version identifier | 
					
						
							| 
									
										
										
										
											2020-08-23 03:54:34 +08:00
										 |  |  | 	 * @param {Snapshot} buildSnapshot snapshot of all build dependencies | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 	 * @param {Set<string>} buildDependencies list of all unresolved build dependencies captured | 
					
						
							| 
									
										
										
										
											2021-04-06 17:28:27 +08:00
										 |  |  | 	 * @param {Map<string, string | false>} resolveResults result of the resolved build dependencies | 
					
						
							| 
									
										
										
										
											2020-08-23 03:54:34 +08:00
										 |  |  | 	 * @param {Snapshot} resolveBuildDependenciesSnapshot snapshot of the dependencies of the build dependencies resolving | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2019-08-20 03:57:49 +08:00
										 |  |  | 	constructor( | 
					
						
							|  |  |  | 		data, | 
					
						
							| 
									
										
										
										
											2019-08-20 18:31:36 +08:00
										 |  |  | 		version, | 
					
						
							| 
									
										
										
										
											2019-08-20 03:57:49 +08:00
										 |  |  | 		buildSnapshot, | 
					
						
							|  |  |  | 		buildDependencies, | 
					
						
							|  |  |  | 		resolveResults, | 
					
						
							|  |  |  | 		resolveBuildDependenciesSnapshot | 
					
						
							|  |  |  | 	) { | 
					
						
							| 
									
										
										
										
											2019-08-13 22:11:40 +08:00
										 |  |  | 		this.data = data; | 
					
						
							| 
									
										
										
										
											2019-08-20 18:31:36 +08:00
										 |  |  | 		this.version = version; | 
					
						
							| 
									
										
										
										
											2019-08-13 22:11:40 +08:00
										 |  |  | 		this.buildSnapshot = buildSnapshot; | 
					
						
							| 
									
										
										
										
											2019-08-14 00:59:17 +08:00
										 |  |  | 		this.buildDependencies = buildDependencies; | 
					
						
							| 
									
										
										
										
											2019-08-20 03:57:49 +08:00
										 |  |  | 		this.resolveResults = resolveResults; | 
					
						
							|  |  |  | 		this.resolveBuildDependenciesSnapshot = resolveBuildDependenciesSnapshot; | 
					
						
							| 
									
										
										
										
											2019-08-13 22:11:40 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 	serialize({ write, writeLazy }) { | 
					
						
							| 
									
										
										
										
											2019-08-20 18:31:36 +08:00
										 |  |  | 		write(this.version); | 
					
						
							| 
									
										
										
										
											2019-08-13 22:11:40 +08:00
										 |  |  | 		write(this.buildSnapshot); | 
					
						
							| 
									
										
										
										
											2019-08-14 00:59:17 +08:00
										 |  |  | 		write(this.buildDependencies); | 
					
						
							| 
									
										
										
										
											2019-08-20 03:57:49 +08:00
										 |  |  | 		write(this.resolveResults); | 
					
						
							|  |  |  | 		write(this.resolveBuildDependenciesSnapshot); | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		writeLazy(this.data); | 
					
						
							| 
									
										
										
										
											2019-08-13 22:11:40 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	deserialize({ read }) { | 
					
						
							| 
									
										
										
										
											2019-08-20 18:31:36 +08:00
										 |  |  | 		this.version = read(); | 
					
						
							| 
									
										
										
										
											2019-08-13 22:11:40 +08:00
										 |  |  | 		this.buildSnapshot = read(); | 
					
						
							| 
									
										
										
										
											2019-08-14 00:59:17 +08:00
										 |  |  | 		this.buildDependencies = read(); | 
					
						
							| 
									
										
										
										
											2019-08-20 03:57:49 +08:00
										 |  |  | 		this.resolveResults = read(); | 
					
						
							|  |  |  | 		this.resolveBuildDependenciesSnapshot = read(); | 
					
						
							| 
									
										
										
										
											2019-08-13 22:11:40 +08:00
										 |  |  | 		this.data = read(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | makeSerializable( | 
					
						
							| 
									
										
										
										
											2019-08-20 18:31:36 +08:00
										 |  |  | 	PackContainer, | 
					
						
							| 
									
										
										
										
											2019-08-13 22:11:40 +08:00
										 |  |  | 	"webpack/lib/cache/PackFileCacheStrategy", | 
					
						
							| 
									
										
										
										
											2019-08-20 18:31:36 +08:00
										 |  |  | 	"PackContainer" | 
					
						
							| 
									
										
										
										
											2019-08-13 22:11:40 +08:00
										 |  |  | ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | const MIN_CONTENT_SIZE = 1024 * 1024; // 1 MB
 | 
					
						
							|  |  |  | const CONTENT_COUNT_TO_MERGE = 10; | 
					
						
							| 
									
										
										
										
											2020-08-24 18:54:22 +08:00
										 |  |  | const MAX_ITEMS_IN_FRESH_PACK = 50000; | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | class PackItemInfo { | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {string} identifier identifier of item | 
					
						
							|  |  |  | 	 * @param {string | null} etag etag of item | 
					
						
							|  |  |  | 	 * @param {any} value fresh value of item | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	constructor(identifier, etag, value) { | 
					
						
							|  |  |  | 		this.identifier = identifier; | 
					
						
							|  |  |  | 		this.etag = etag; | 
					
						
							|  |  |  | 		this.location = -1; | 
					
						
							|  |  |  | 		this.lastAccess = Date.now(); | 
					
						
							|  |  |  | 		this.freshValue = value; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | class Pack { | 
					
						
							| 
									
										
										
										
											2021-04-01 22:59:00 +08:00
										 |  |  | 	constructor(logger, maxAge) { | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		/** @type {Map<string, PackItemInfo>} */ | 
					
						
							|  |  |  | 		this.itemInfo = new Map(); | 
					
						
							| 
									
										
										
										
											2020-08-24 18:54:22 +08:00
										 |  |  | 		/** @type {string[]} */ | 
					
						
							|  |  |  | 		this.requests = []; | 
					
						
							|  |  |  | 		/** @type {Map<string, PackItemInfo>} */ | 
					
						
							|  |  |  | 		this.freshContent = new Map(); | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		/** @type {(undefined | PackContent)[]} */ | 
					
						
							|  |  |  | 		this.content = []; | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 		this.invalid = false; | 
					
						
							| 
									
										
										
										
											2019-08-12 19:41:23 +08:00
										 |  |  | 		this.logger = logger; | 
					
						
							| 
									
										
										
										
											2021-04-01 22:59:00 +08:00
										 |  |  | 		this.maxAge = maxAge; | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-12 20:55:13 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {string} identifier unique name for the resource | 
					
						
							|  |  |  | 	 * @param {string | null} etag etag of the resource | 
					
						
							|  |  |  | 	 * @returns {any} cached content | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 	get(identifier, etag) { | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		const info = this.itemInfo.get(identifier); | 
					
						
							| 
									
										
										
										
											2020-08-24 18:54:22 +08:00
										 |  |  | 		this.requests.push(identifier); | 
					
						
							|  |  |  | 		if (info === undefined) { | 
					
						
							|  |  |  | 			return undefined; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		if (info.etag !== etag) return null; | 
					
						
							|  |  |  | 		info.lastAccess = Date.now(); | 
					
						
							|  |  |  | 		const loc = info.location; | 
					
						
							|  |  |  | 		if (loc === -1) { | 
					
						
							|  |  |  | 			return info.freshValue; | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 			if (!this.content[loc]) { | 
					
						
							|  |  |  | 				return undefined; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return this.content[loc].get(identifier); | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-12 20:55:13 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {string} identifier unique name for the resource | 
					
						
							|  |  |  | 	 * @param {string | null} etag etag of the resource | 
					
						
							|  |  |  | 	 * @param {any} data cached content | 
					
						
							|  |  |  | 	 * @returns {void} | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 	set(identifier, etag, data) { | 
					
						
							| 
									
										
										
										
											2019-08-14 00:53:41 +08:00
										 |  |  | 		if (!this.invalid) { | 
					
						
							|  |  |  | 			this.invalid = true; | 
					
						
							| 
									
										
										
										
											2020-08-24 18:54:22 +08:00
										 |  |  | 			this.logger.log(`Pack got invalid because of write to: ${identifier}`); | 
					
						
							| 
									
										
										
										
											2019-08-14 00:53:41 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		const info = this.itemInfo.get(identifier); | 
					
						
							|  |  |  | 		if (info === undefined) { | 
					
						
							|  |  |  | 			const newInfo = new PackItemInfo(identifier, etag, data); | 
					
						
							|  |  |  | 			this.itemInfo.set(identifier, newInfo); | 
					
						
							| 
									
										
										
										
											2020-08-24 18:54:22 +08:00
										 |  |  | 			this.requests.push(identifier); | 
					
						
							|  |  |  | 			this.freshContent.set(identifier, newInfo); | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			const loc = info.location; | 
					
						
							|  |  |  | 			if (loc >= 0) { | 
					
						
							| 
									
										
										
										
											2020-08-24 18:54:22 +08:00
										 |  |  | 				this.requests.push(identifier); | 
					
						
							|  |  |  | 				this.freshContent.set(identifier, info); | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 				const content = this.content[loc]; | 
					
						
							|  |  |  | 				content.delete(identifier); | 
					
						
							|  |  |  | 				if (content.items.size === 0) { | 
					
						
							|  |  |  | 					this.content[loc] = undefined; | 
					
						
							|  |  |  | 					this.logger.debug("Pack %d got empty and is removed", loc); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			info.freshValue = data; | 
					
						
							|  |  |  | 			info.lastAccess = Date.now(); | 
					
						
							|  |  |  | 			info.etag = etag; | 
					
						
							|  |  |  | 			info.location = -1; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-01 22:59:00 +08:00
										 |  |  | 	getContentStats() { | 
					
						
							|  |  |  | 		let count = 0; | 
					
						
							|  |  |  | 		let size = 0; | 
					
						
							|  |  |  | 		for (const content of this.content) { | 
					
						
							|  |  |  | 			if (content !== undefined) { | 
					
						
							|  |  |  | 				count++; | 
					
						
							|  |  |  | 				const s = content.getSize(); | 
					
						
							|  |  |  | 				if (s > 0) { | 
					
						
							|  |  |  | 					size += s; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return { count, size }; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @returns {number} new location of data entries | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	_findLocation() { | 
					
						
							|  |  |  | 		let i; | 
					
						
							|  |  |  | 		for (i = 0; i < this.content.length && this.content[i] !== undefined; i++); | 
					
						
							|  |  |  | 		return i; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	_gcAndUpdateLocation(items, usedItems, newLoc) { | 
					
						
							|  |  |  | 		let count = 0; | 
					
						
							|  |  |  | 		let lastGC; | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 		const now = Date.now(); | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		for (const identifier of items) { | 
					
						
							|  |  |  | 			const info = this.itemInfo.get(identifier); | 
					
						
							| 
									
										
										
										
											2021-04-01 22:59:00 +08:00
										 |  |  | 			if (now - info.lastAccess > this.maxAge) { | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 				this.itemInfo.delete(identifier); | 
					
						
							|  |  |  | 				items.delete(identifier); | 
					
						
							|  |  |  | 				usedItems.delete(identifier); | 
					
						
							|  |  |  | 				count++; | 
					
						
							|  |  |  | 				lastGC = identifier; | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				info.location = newLoc; | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		if (count > 0) { | 
					
						
							|  |  |  | 			this.logger.log( | 
					
						
							| 
									
										
										
										
											2021-04-01 22:59:00 +08:00
										 |  |  | 				"Garbage Collected %d old items at pack %d (%d items remaining) e. g. %s", | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 				count, | 
					
						
							|  |  |  | 				newLoc, | 
					
						
							| 
									
										
										
										
											2021-04-01 22:59:00 +08:00
										 |  |  | 				items.size, | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 				lastGC | 
					
						
							|  |  |  | 			); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 	_persistFreshContent() { | 
					
						
							| 
									
										
										
										
											2020-08-24 18:54:22 +08:00
										 |  |  | 		if (this.freshContent.size > 0) { | 
					
						
							|  |  |  | 			const packCount = Math.ceil( | 
					
						
							|  |  |  | 				this.freshContent.size / MAX_ITEMS_IN_FRESH_PACK | 
					
						
							|  |  |  | 			); | 
					
						
							|  |  |  | 			const itemsPerPack = Math.ceil(this.freshContent.size / packCount); | 
					
						
							|  |  |  | 			this.logger.log(`${this.freshContent.size} fresh items in cache`); | 
					
						
							|  |  |  | 			const packs = Array.from({ length: packCount }, () => { | 
					
						
							|  |  |  | 				const loc = this._findLocation(); | 
					
						
							|  |  |  | 				this.content[loc] = null; // reserve
 | 
					
						
							|  |  |  | 				return { | 
					
						
							|  |  |  | 					/** @type {Set<string>} */ | 
					
						
							|  |  |  | 					items: new Set(), | 
					
						
							|  |  |  | 					/** @type {Map<string, any>} */ | 
					
						
							|  |  |  | 					map: new Map(), | 
					
						
							|  |  |  | 					loc | 
					
						
							|  |  |  | 				}; | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 			let i = 0; | 
					
						
							|  |  |  | 			let pack = packs[0]; | 
					
						
							|  |  |  | 			let packIndex = 0; | 
					
						
							|  |  |  | 			for (const identifier of this.requests) { | 
					
						
							|  |  |  | 				const info = this.freshContent.get(identifier); | 
					
						
							|  |  |  | 				if (info === undefined) continue; | 
					
						
							|  |  |  | 				pack.items.add(identifier); | 
					
						
							|  |  |  | 				pack.map.set(identifier, info.freshValue); | 
					
						
							|  |  |  | 				info.location = pack.loc; | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 				info.freshValue = undefined; | 
					
						
							| 
									
										
										
										
											2020-08-24 18:54:22 +08:00
										 |  |  | 				this.freshContent.delete(identifier); | 
					
						
							|  |  |  | 				if (++i > itemsPerPack) { | 
					
						
							|  |  |  | 					i = 0; | 
					
						
							|  |  |  | 					pack = packs[++packIndex]; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			for (const pack of packs) { | 
					
						
							|  |  |  | 				this.content[pack.loc] = new PackContent( | 
					
						
							|  |  |  | 					pack.items, | 
					
						
							|  |  |  | 					new Set(pack.items), | 
					
						
							|  |  |  | 					new PackContentItems(pack.map) | 
					
						
							|  |  |  | 				); | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * Merges small content files to a single content file | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	_optimizeSmallContent() { | 
					
						
							|  |  |  | 		// 1. Find all small content files
 | 
					
						
							| 
									
										
										
										
											2020-03-13 00:51:26 +08:00
										 |  |  | 		// Treat unused content files separately to avoid
 | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		// a merge-split cycle
 | 
					
						
							|  |  |  | 		/** @type {number[]} */ | 
					
						
							|  |  |  | 		const smallUsedContents = []; | 
					
						
							|  |  |  | 		/** @type {number} */ | 
					
						
							|  |  |  | 		let smallUsedContentSize = 0; | 
					
						
							|  |  |  | 		/** @type {number[]} */ | 
					
						
							|  |  |  | 		const smallUnusedContents = []; | 
					
						
							|  |  |  | 		/** @type {number} */ | 
					
						
							|  |  |  | 		let smallUnusedContentSize = 0; | 
					
						
							|  |  |  | 		for (let i = 0; i < this.content.length; i++) { | 
					
						
							|  |  |  | 			const content = this.content[i]; | 
					
						
							|  |  |  | 			if (content === undefined) continue; | 
					
						
							|  |  |  | 			if (content.outdated) continue; | 
					
						
							|  |  |  | 			const size = content.getSize(); | 
					
						
							|  |  |  | 			if (size < 0 || size > MIN_CONTENT_SIZE) continue; | 
					
						
							|  |  |  | 			if (content.used.size > 0) { | 
					
						
							|  |  |  | 				smallUsedContents.push(i); | 
					
						
							|  |  |  | 				smallUsedContentSize += size; | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 				smallUnusedContents.push(i); | 
					
						
							|  |  |  | 				smallUnusedContentSize += size; | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-10 09:59:46 +08:00
										 |  |  | 		// 2. Check if minimum number is reached
 | 
					
						
							| 
									
										
										
										
											2020-01-28 15:42:49 +08:00
										 |  |  | 		let mergedIndices; | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		if ( | 
					
						
							|  |  |  | 			smallUsedContents.length >= CONTENT_COUNT_TO_MERGE || | 
					
						
							|  |  |  | 			smallUsedContentSize > MIN_CONTENT_SIZE | 
					
						
							|  |  |  | 		) { | 
					
						
							| 
									
										
										
										
											2020-01-28 15:42:49 +08:00
										 |  |  | 			mergedIndices = smallUsedContents; | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		} else if ( | 
					
						
							|  |  |  | 			smallUnusedContents.length >= CONTENT_COUNT_TO_MERGE || | 
					
						
							|  |  |  | 			smallUnusedContentSize > MIN_CONTENT_SIZE | 
					
						
							|  |  |  | 		) { | 
					
						
							| 
									
										
										
										
											2020-01-28 15:42:49 +08:00
										 |  |  | 			mergedIndices = smallUnusedContents; | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		} else return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-28 15:42:49 +08:00
										 |  |  | 		const mergedContent = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// 3. Remove old content entries
 | 
					
						
							|  |  |  | 		for (const i of mergedIndices) { | 
					
						
							|  |  |  | 			mergedContent.push(this.content[i]); | 
					
						
							|  |  |  | 			this.content[i] = undefined; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		// 4. Determine merged items
 | 
					
						
							|  |  |  | 		/** @type {Set<string>} */ | 
					
						
							|  |  |  | 		const mergedItems = new Set(); | 
					
						
							|  |  |  | 		/** @type {Set<string>} */ | 
					
						
							|  |  |  | 		const mergedUsedItems = new Set(); | 
					
						
							| 
									
										
										
										
											2020-01-28 15:42:49 +08:00
										 |  |  | 		/** @type {(function(Map<string, any>): Promise)[]} */ | 
					
						
							|  |  |  | 		const addToMergedMap = []; | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		for (const content of mergedContent) { | 
					
						
							|  |  |  | 			for (const identifier of content.items) { | 
					
						
							|  |  |  | 				mergedItems.add(identifier); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			for (const identifer of content.used) { | 
					
						
							|  |  |  | 				mergedUsedItems.add(identifer); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2020-01-28 15:42:49 +08:00
										 |  |  | 			addToMergedMap.push(async map => { | 
					
						
							|  |  |  | 				// unpack existing content
 | 
					
						
							|  |  |  | 				// after that values are accessible in .content
 | 
					
						
							|  |  |  | 				await content.unpack(); | 
					
						
							|  |  |  | 				for (const [identifier, value] of content.content) { | 
					
						
							|  |  |  | 					map.set(identifier, value); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// 5. GC and update location of merged items
 | 
					
						
							|  |  |  | 		const newLoc = this._findLocation(); | 
					
						
							|  |  |  | 		this._gcAndUpdateLocation(mergedItems, mergedUsedItems, newLoc); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// 6. If not empty, store content somewhere
 | 
					
						
							|  |  |  | 		if (mergedItems.size > 0) { | 
					
						
							|  |  |  | 			this.content[newLoc] = new PackContent( | 
					
						
							|  |  |  | 				mergedItems, | 
					
						
							|  |  |  | 				mergedUsedItems, | 
					
						
							| 
									
										
										
										
											2020-12-27 05:32:57 +08:00
										 |  |  | 				memoize(async () => { | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 					/** @type {Map<string, any>} */ | 
					
						
							|  |  |  | 					const map = new Map(); | 
					
						
							| 
									
										
										
										
											2020-01-28 15:42:49 +08:00
										 |  |  | 					await Promise.all(addToMergedMap.map(fn => fn(map))); | 
					
						
							| 
									
										
										
										
											2020-08-20 02:04:34 +08:00
										 |  |  | 					return new PackContentItems(map); | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 				}) | 
					
						
							|  |  |  | 			); | 
					
						
							|  |  |  | 			this.logger.log( | 
					
						
							|  |  |  | 				"Merged %d small files with %d cache items into pack %d", | 
					
						
							|  |  |  | 				mergedContent.length, | 
					
						
							|  |  |  | 				mergedItems.size, | 
					
						
							|  |  |  | 				newLoc | 
					
						
							|  |  |  | 			); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * Split large content files with used and unused items | 
					
						
							|  |  |  | 	 * into two parts to separate used from unused items | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	_optimizeUnusedContent() { | 
					
						
							|  |  |  | 		// 1. Find a large content file with used and unused items
 | 
					
						
							|  |  |  | 		for (let i = 0; i < this.content.length; i++) { | 
					
						
							|  |  |  | 			const content = this.content[i]; | 
					
						
							|  |  |  | 			if (content === undefined) continue; | 
					
						
							|  |  |  | 			const size = content.getSize(); | 
					
						
							|  |  |  | 			if (size < MIN_CONTENT_SIZE) continue; | 
					
						
							|  |  |  | 			const used = content.used.size; | 
					
						
							|  |  |  | 			const total = content.items.size; | 
					
						
							|  |  |  | 			if (used > 0 && used < total) { | 
					
						
							|  |  |  | 				// 2. Remove this content
 | 
					
						
							|  |  |  | 				this.content[i] = undefined; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// 3. Determine items for the used content file
 | 
					
						
							|  |  |  | 				const usedItems = new Set(content.used); | 
					
						
							|  |  |  | 				const newLoc = this._findLocation(); | 
					
						
							|  |  |  | 				this._gcAndUpdateLocation(usedItems, usedItems, newLoc); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// 4. Create content file for used items
 | 
					
						
							|  |  |  | 				if (usedItems.size > 0) { | 
					
						
							|  |  |  | 					this.content[newLoc] = new PackContent( | 
					
						
							|  |  |  | 						usedItems, | 
					
						
							|  |  |  | 						new Set(usedItems), | 
					
						
							|  |  |  | 						async () => { | 
					
						
							|  |  |  | 							await content.unpack(); | 
					
						
							|  |  |  | 							const map = new Map(); | 
					
						
							|  |  |  | 							for (const identifier of usedItems) { | 
					
						
							|  |  |  | 								map.set(identifier, content.content.get(identifier)); | 
					
						
							|  |  |  | 							} | 
					
						
							| 
									
										
										
										
											2020-08-20 02:04:34 +08:00
										 |  |  | 							return new PackContentItems(map); | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 						} | 
					
						
							|  |  |  | 					); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// 5. Determine items for the unused content file
 | 
					
						
							|  |  |  | 				const unusedItems = new Set(content.items); | 
					
						
							|  |  |  | 				const usedOfUnusedItems = new Set(); | 
					
						
							|  |  |  | 				for (const identifier of usedItems) { | 
					
						
							|  |  |  | 					unusedItems.delete(identifier); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				const newUnusedLoc = this._findLocation(); | 
					
						
							|  |  |  | 				this._gcAndUpdateLocation(unusedItems, usedOfUnusedItems, newUnusedLoc); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// 6. Create content file for unused items
 | 
					
						
							|  |  |  | 				if (unusedItems.size > 0) { | 
					
						
							|  |  |  | 					this.content[newUnusedLoc] = new PackContent( | 
					
						
							|  |  |  | 						unusedItems, | 
					
						
							|  |  |  | 						usedOfUnusedItems, | 
					
						
							|  |  |  | 						async () => { | 
					
						
							|  |  |  | 							await content.unpack(); | 
					
						
							|  |  |  | 							const map = new Map(); | 
					
						
							|  |  |  | 							for (const identifier of unusedItems) { | 
					
						
							|  |  |  | 								map.set(identifier, content.content.get(identifier)); | 
					
						
							|  |  |  | 							} | 
					
						
							| 
									
										
										
										
											2020-08-20 02:04:34 +08:00
										 |  |  | 							return new PackContentItems(map); | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 						} | 
					
						
							|  |  |  | 					); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				this.logger.log( | 
					
						
							|  |  |  | 					"Split pack %d into pack %d with %d used items and pack %d with %d unused items", | 
					
						
							|  |  |  | 					i, | 
					
						
							|  |  |  | 					newLoc, | 
					
						
							|  |  |  | 					usedItems.size, | 
					
						
							|  |  |  | 					newUnusedLoc, | 
					
						
							|  |  |  | 					unusedItems.size | 
					
						
							|  |  |  | 				); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// optimizing only one of them is good enough and
 | 
					
						
							|  |  |  | 				// reduces the amount of serialization needed
 | 
					
						
							|  |  |  | 				return; | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-01 22:59:00 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * Find the content with the oldest item and run GC on that. | 
					
						
							|  |  |  | 	 * Only runs for one content to avoid large invalidation. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	_gcOldestContent() { | 
					
						
							|  |  |  | 		/** @type {PackItemInfo} */ | 
					
						
							|  |  |  | 		let oldest = undefined; | 
					
						
							|  |  |  | 		for (const info of this.itemInfo.values()) { | 
					
						
							|  |  |  | 			if (oldest === undefined || info.lastAccess < oldest.lastAccess) { | 
					
						
							|  |  |  | 				oldest = info; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (Date.now() - oldest.lastAccess > this.maxAge) { | 
					
						
							|  |  |  | 			const loc = oldest.location; | 
					
						
							|  |  |  | 			if (loc < 0) return; | 
					
						
							|  |  |  | 			const content = this.content[loc]; | 
					
						
							|  |  |  | 			const items = new Set(content.items); | 
					
						
							|  |  |  | 			const usedItems = new Set(content.used); | 
					
						
							|  |  |  | 			this._gcAndUpdateLocation(items, usedItems, loc); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			this.content[loc] = | 
					
						
							|  |  |  | 				items.size > 0 | 
					
						
							|  |  |  | 					? new PackContent(items, usedItems, async () => { | 
					
						
							|  |  |  | 							await content.unpack(); | 
					
						
							|  |  |  | 							const map = new Map(); | 
					
						
							|  |  |  | 							for (const identifier of items) { | 
					
						
							|  |  |  | 								map.set(identifier, content.content.get(identifier)); | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 							return new PackContentItems(map); | 
					
						
							|  |  |  | 					  }) | 
					
						
							|  |  |  | 					: undefined; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 	serialize({ write, writeSeparate }) { | 
					
						
							|  |  |  | 		this._persistFreshContent(); | 
					
						
							|  |  |  | 		this._optimizeSmallContent(); | 
					
						
							|  |  |  | 		this._optimizeUnusedContent(); | 
					
						
							| 
									
										
										
										
											2021-04-01 22:59:00 +08:00
										 |  |  | 		this._gcOldestContent(); | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		for (const identifier of this.itemInfo.keys()) { | 
					
						
							|  |  |  | 			write(identifier); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-01-29 17:38:31 +08:00
										 |  |  | 		write(null); // null as marker of the end of keys
 | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		for (const info of this.itemInfo.values()) { | 
					
						
							|  |  |  | 			write(info.etag); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		for (const info of this.itemInfo.values()) { | 
					
						
							|  |  |  | 			write(info.lastAccess); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		for (let i = 0; i < this.content.length; i++) { | 
					
						
							|  |  |  | 			const content = this.content[i]; | 
					
						
							|  |  |  | 			if (content !== undefined) { | 
					
						
							|  |  |  | 				write(content.items); | 
					
						
							| 
									
										
										
										
											2020-08-20 02:04:34 +08:00
										 |  |  | 				writeSeparate(content.getLazyContentItems(), { name: `${i}` }); | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2020-01-29 17:38:31 +08:00
										 |  |  | 				write(undefined); // undefined marks an empty content slot
 | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-01-29 17:38:31 +08:00
										 |  |  | 		write(null); // null as marker of the end of items
 | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 	deserialize({ read, logger }) { | 
					
						
							|  |  |  | 		this.logger = logger; | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			const items = []; | 
					
						
							|  |  |  | 			let item = read(); | 
					
						
							|  |  |  | 			while (item !== null) { | 
					
						
							|  |  |  | 				items.push(item); | 
					
						
							|  |  |  | 				item = read(); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			this.itemInfo.clear(); | 
					
						
							|  |  |  | 			const infoItems = items.map(identifier => { | 
					
						
							|  |  |  | 				const info = new PackItemInfo(identifier, undefined, undefined); | 
					
						
							|  |  |  | 				this.itemInfo.set(identifier, info); | 
					
						
							|  |  |  | 				return info; | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 			for (const info of infoItems) { | 
					
						
							|  |  |  | 				info.etag = read(); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			for (const info of infoItems) { | 
					
						
							|  |  |  | 				info.lastAccess = read(); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		this.content.length = 0; | 
					
						
							|  |  |  | 		let items = read(); | 
					
						
							|  |  |  | 		while (items !== null) { | 
					
						
							|  |  |  | 			if (items === undefined) { | 
					
						
							|  |  |  | 				this.content.push(items); | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 				const idx = this.content.length; | 
					
						
							|  |  |  | 				const lazy = read(); | 
					
						
							| 
									
										
										
										
											2020-01-30 18:34:33 +08:00
										 |  |  | 				this.content.push( | 
					
						
							|  |  |  | 					new PackContent( | 
					
						
							|  |  |  | 						items, | 
					
						
							|  |  |  | 						new Set(), | 
					
						
							|  |  |  | 						lazy, | 
					
						
							|  |  |  | 						logger, | 
					
						
							|  |  |  | 						`${this.content.length}` | 
					
						
							|  |  |  | 					) | 
					
						
							|  |  |  | 				); | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 				for (const identifier of items) { | 
					
						
							|  |  |  | 					this.itemInfo.get(identifier).location = idx; | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 			items = read(); | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | makeSerializable(Pack, "webpack/lib/cache/PackFileCacheStrategy", "Pack"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-20 02:04:34 +08:00
										 |  |  | class PackContentItems { | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {Map<string, any>} map items | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	constructor(map) { | 
					
						
							|  |  |  | 		this.map = map; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-27 17:06:01 +08:00
										 |  |  | 	serialize({ write, snapshot, rollback, logger, profile }) { | 
					
						
							|  |  |  | 		if (profile) { | 
					
						
							|  |  |  | 			write(false); | 
					
						
							|  |  |  | 			for (const [key, value] of this.map) { | 
					
						
							|  |  |  | 				const s = snapshot(); | 
					
						
							|  |  |  | 				try { | 
					
						
							|  |  |  | 					write(key); | 
					
						
							|  |  |  | 					const start = process.hrtime(); | 
					
						
							|  |  |  | 					write(value); | 
					
						
							|  |  |  | 					const durationHr = process.hrtime(start); | 
					
						
							|  |  |  | 					const duration = durationHr[0] * 1000 + durationHr[1] / 1e6; | 
					
						
							|  |  |  | 					if (duration > 1) { | 
					
						
							|  |  |  | 						if (duration > 500) | 
					
						
							|  |  |  | 							logger.error(`Serialization of '${key}': ${duration} ms`); | 
					
						
							|  |  |  | 						else if (duration > 50) | 
					
						
							|  |  |  | 							logger.warn(`Serialization of '${key}': ${duration} ms`); | 
					
						
							|  |  |  | 						else if (duration > 10) | 
					
						
							|  |  |  | 							logger.info(`Serialization of '${key}': ${duration} ms`); | 
					
						
							|  |  |  | 						else if (duration > 5) | 
					
						
							|  |  |  | 							logger.log(`Serialization of '${key}': ${duration} ms`); | 
					
						
							|  |  |  | 						else logger.debug(`Serialization of '${key}': ${duration} ms`); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} catch (e) { | 
					
						
							|  |  |  | 					rollback(s); | 
					
						
							|  |  |  | 					if (e === NOT_SERIALIZABLE) continue; | 
					
						
							|  |  |  | 					logger.warn( | 
					
						
							|  |  |  | 						`Skipped not serializable cache item '${key}': ${e.message}` | 
					
						
							|  |  |  | 					); | 
					
						
							|  |  |  | 					logger.debug(e.stack); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			write(null); | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-08-20 02:04:34 +08:00
										 |  |  | 		// Try to serialize all at once
 | 
					
						
							|  |  |  | 		const s = snapshot(); | 
					
						
							|  |  |  | 		try { | 
					
						
							|  |  |  | 			write(true); | 
					
						
							|  |  |  | 			write(this.map); | 
					
						
							|  |  |  | 		} catch (e) { | 
					
						
							|  |  |  | 			rollback(s); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Try to serialize each item on it's own
 | 
					
						
							|  |  |  | 			write(false); | 
					
						
							|  |  |  | 			for (const [key, value] of this.map) { | 
					
						
							|  |  |  | 				const s = snapshot(); | 
					
						
							|  |  |  | 				try { | 
					
						
							|  |  |  | 					write(key); | 
					
						
							|  |  |  | 					write(value); | 
					
						
							|  |  |  | 				} catch (e) { | 
					
						
							|  |  |  | 					rollback(s); | 
					
						
							| 
									
										
										
										
											2021-01-21 23:32:49 +08:00
										 |  |  | 					if (e === NOT_SERIALIZABLE) continue; | 
					
						
							| 
									
										
										
										
											2020-08-20 02:04:34 +08:00
										 |  |  | 					logger.warn( | 
					
						
							|  |  |  | 						`Skipped not serializable cache item '${key}': ${e.message}` | 
					
						
							|  |  |  | 					); | 
					
						
							|  |  |  | 					logger.debug(e.stack); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			write(null); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-27 17:06:01 +08:00
										 |  |  | 	deserialize({ read, logger, profile }) { | 
					
						
							| 
									
										
										
										
											2020-08-20 02:04:34 +08:00
										 |  |  | 		if (read()) { | 
					
						
							|  |  |  | 			this.map = read(); | 
					
						
							| 
									
										
										
										
											2021-04-27 17:06:01 +08:00
										 |  |  | 		} else if (profile) { | 
					
						
							|  |  |  | 			const map = new Map(); | 
					
						
							|  |  |  | 			let key = read(); | 
					
						
							|  |  |  | 			while (key !== null) { | 
					
						
							|  |  |  | 				const start = process.hrtime(); | 
					
						
							|  |  |  | 				const value = read(); | 
					
						
							|  |  |  | 				const durationHr = process.hrtime(start); | 
					
						
							|  |  |  | 				const duration = durationHr[0] * 1000 + durationHr[1] / 1e6; | 
					
						
							|  |  |  | 				if (duration > 1) { | 
					
						
							|  |  |  | 					if (duration > 100) | 
					
						
							|  |  |  | 						logger.error(`Deserialization of '${key}': ${duration} ms`); | 
					
						
							|  |  |  | 					else if (duration > 20) | 
					
						
							|  |  |  | 						logger.warn(`Deserialization of '${key}': ${duration} ms`); | 
					
						
							|  |  |  | 					else if (duration > 5) | 
					
						
							|  |  |  | 						logger.info(`Deserialization of '${key}': ${duration} ms`); | 
					
						
							|  |  |  | 					else if (duration > 2) | 
					
						
							|  |  |  | 						logger.log(`Deserialization of '${key}': ${duration} ms`); | 
					
						
							|  |  |  | 					else logger.debug(`Deserialization of '${key}': ${duration} ms`); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				map.set(key, value); | 
					
						
							|  |  |  | 				key = read(); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			this.map = map; | 
					
						
							| 
									
										
										
										
											2020-08-20 02:04:34 +08:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			const map = new Map(); | 
					
						
							|  |  |  | 			let key = read(); | 
					
						
							|  |  |  | 			while (key !== null) { | 
					
						
							|  |  |  | 				map.set(key, read()); | 
					
						
							|  |  |  | 				key = read(); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			this.map = map; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | makeSerializable( | 
					
						
							|  |  |  | 	PackContentItems, | 
					
						
							|  |  |  | 	"webpack/lib/cache/PackFileCacheStrategy", | 
					
						
							|  |  |  | 	"PackContentItems" | 
					
						
							|  |  |  | ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | class PackContent { | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {Set<string>} items keys | 
					
						
							|  |  |  | 	 * @param {Set<string>} usedItems used keys | 
					
						
							| 
									
										
										
										
											2020-08-20 02:04:34 +08:00
										 |  |  | 	 * @param {PackContentItems | function(): Promise<PackContentItems>} dataOrFn sync or async content | 
					
						
							| 
									
										
										
										
											2020-01-30 18:34:33 +08:00
										 |  |  | 	 * @param {Logger=} logger logger for logging | 
					
						
							|  |  |  | 	 * @param {string=} lazyName name of dataOrFn for logging | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2020-01-30 18:34:33 +08:00
										 |  |  | 	constructor(items, usedItems, dataOrFn, logger, lazyName) { | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		this.items = items; | 
					
						
							| 
									
										
										
										
											2020-08-20 02:04:34 +08:00
										 |  |  | 		/** @type {function(): PackContentItems | Promise<PackContentItems>} */ | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		this.lazy = typeof dataOrFn === "function" ? dataOrFn : undefined; | 
					
						
							|  |  |  | 		/** @type {Map<string, any>} */ | 
					
						
							| 
									
										
										
										
											2020-08-20 02:04:34 +08:00
										 |  |  | 		this.content = typeof dataOrFn === "function" ? undefined : dataOrFn.map; | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		this.outdated = false; | 
					
						
							|  |  |  | 		this.used = usedItems; | 
					
						
							| 
									
										
										
										
											2020-01-30 18:34:33 +08:00
										 |  |  | 		this.logger = logger; | 
					
						
							|  |  |  | 		this.lazyName = lazyName; | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	get(identifier) { | 
					
						
							|  |  |  | 		this.used.add(identifier); | 
					
						
							|  |  |  | 		if (this.content) { | 
					
						
							|  |  |  | 			return this.content.get(identifier); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-01-30 18:34:33 +08:00
										 |  |  | 		const { lazyName } = this; | 
					
						
							| 
									
										
										
										
											2020-08-24 18:54:22 +08:00
										 |  |  | 		let timeMessage; | 
					
						
							| 
									
										
										
										
											2020-01-30 18:34:33 +08:00
										 |  |  | 		if (lazyName) { | 
					
						
							|  |  |  | 			// only log once
 | 
					
						
							|  |  |  | 			this.lazyName = undefined; | 
					
						
							| 
									
										
										
										
											2020-08-24 18:54:22 +08:00
										 |  |  | 			timeMessage = `restore cache content ${lazyName} (${formatSize( | 
					
						
							|  |  |  | 				this.getSize() | 
					
						
							|  |  |  | 			)})`;
 | 
					
						
							|  |  |  | 			this.logger.log( | 
					
						
							|  |  |  | 				`starting to restore cache content ${lazyName} (${formatSize( | 
					
						
							|  |  |  | 					this.getSize() | 
					
						
							|  |  |  | 				)}) because of request to: ${identifier}`
 | 
					
						
							|  |  |  | 			); | 
					
						
							|  |  |  | 			this.logger.time(timeMessage); | 
					
						
							| 
									
										
										
										
											2020-01-30 18:34:33 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		const value = this.lazy(); | 
					
						
							|  |  |  | 		if (value instanceof Promise) { | 
					
						
							|  |  |  | 			return value.then(data => { | 
					
						
							| 
									
										
										
										
											2020-08-20 02:04:34 +08:00
										 |  |  | 				const map = data.map; | 
					
						
							| 
									
										
										
										
											2020-08-24 18:54:22 +08:00
										 |  |  | 				if (timeMessage) { | 
					
						
							|  |  |  | 					this.logger.timeEnd(timeMessage); | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2020-08-20 02:04:34 +08:00
										 |  |  | 				this.content = map; | 
					
						
							|  |  |  | 				return map.get(identifier); | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 			}); | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2020-08-20 02:04:34 +08:00
										 |  |  | 			const map = value.map; | 
					
						
							| 
									
										
										
										
											2020-08-24 18:54:22 +08:00
										 |  |  | 			if (timeMessage) { | 
					
						
							|  |  |  | 				this.logger.timeEnd(timeMessage); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2020-08-20 02:04:34 +08:00
										 |  |  | 			this.content = map; | 
					
						
							|  |  |  | 			return map.get(identifier); | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @returns {void | Promise} maybe a promise if lazy | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	unpack() { | 
					
						
							|  |  |  | 		if (this.content) return; | 
					
						
							|  |  |  | 		if (this.lazy) { | 
					
						
							| 
									
										
										
										
											2020-08-24 18:54:22 +08:00
										 |  |  | 			const { lazyName } = this; | 
					
						
							|  |  |  | 			let timeMessage; | 
					
						
							|  |  |  | 			if (lazyName) { | 
					
						
							|  |  |  | 				// only log once
 | 
					
						
							|  |  |  | 				this.lazyName = undefined; | 
					
						
							|  |  |  | 				timeMessage = `unpack cache content ${lazyName} (${formatSize( | 
					
						
							|  |  |  | 					this.getSize() | 
					
						
							|  |  |  | 				)})`;
 | 
					
						
							|  |  |  | 				this.logger.time(timeMessage); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 			const value = this.lazy(); | 
					
						
							|  |  |  | 			if (value instanceof Promise) { | 
					
						
							|  |  |  | 				return value.then(data => { | 
					
						
							| 
									
										
										
										
											2020-08-24 18:54:22 +08:00
										 |  |  | 					if (timeMessage) { | 
					
						
							|  |  |  | 						this.logger.timeEnd(timeMessage); | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2020-08-20 02:04:34 +08:00
										 |  |  | 					this.content = data.map; | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 				}); | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2020-08-24 18:54:22 +08:00
										 |  |  | 				if (timeMessage) { | 
					
						
							|  |  |  | 					this.logger.timeEnd(timeMessage); | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2020-08-20 02:04:34 +08:00
										 |  |  | 				this.content = value.map; | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @returns {number} size of the content or -1 if not known | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	getSize() { | 
					
						
							|  |  |  | 		if (!this.lazy) return -1; | 
					
						
							|  |  |  | 		const options = /** @type {any} */ (this.lazy).options; | 
					
						
							|  |  |  | 		if (!options) return -1; | 
					
						
							|  |  |  | 		const size = options.size; | 
					
						
							|  |  |  | 		if (typeof size !== "number") return -1; | 
					
						
							|  |  |  | 		return size; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	delete(identifier) { | 
					
						
							|  |  |  | 		this.items.delete(identifier); | 
					
						
							|  |  |  | 		this.used.delete(identifier); | 
					
						
							|  |  |  | 		this.outdated = true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							| 
									
										
										
										
											2020-08-20 02:04:34 +08:00
										 |  |  | 	 * @returns {function(): PackContentItems | Promise<PackContentItems>} lazy content items | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2020-08-20 02:04:34 +08:00
										 |  |  | 	getLazyContentItems() { | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		if (!this.outdated && this.lazy) return this.lazy; | 
					
						
							|  |  |  | 		if (!this.outdated && this.content) { | 
					
						
							|  |  |  | 			const map = new Map(this.content); | 
					
						
							| 
									
										
										
										
											2020-12-27 05:32:57 +08:00
										 |  |  | 			return (this.lazy = memoize(() => new PackContentItems(map))); | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		this.outdated = false; | 
					
						
							|  |  |  | 		if (this.content) { | 
					
						
							| 
									
										
										
										
											2020-12-27 05:32:57 +08:00
										 |  |  | 			return (this.lazy = memoize(() => { | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 				/** @type {Map<string, any>} */ | 
					
						
							|  |  |  | 				const map = new Map(); | 
					
						
							|  |  |  | 				for (const item of this.items) { | 
					
						
							|  |  |  | 					map.set(item, this.content.get(item)); | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2020-08-20 02:04:34 +08:00
										 |  |  | 				return new PackContentItems(map); | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 			})); | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		const lazy = this.lazy; | 
					
						
							|  |  |  | 		return (this.lazy = () => { | 
					
						
							|  |  |  | 			const value = lazy(); | 
					
						
							|  |  |  | 			if (value instanceof Promise) { | 
					
						
							|  |  |  | 				return value.then(data => { | 
					
						
							| 
									
										
										
										
											2020-08-20 02:04:34 +08:00
										 |  |  | 					const oldMap = data.map; | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 					/** @type {Map<string, any>} */ | 
					
						
							|  |  |  | 					const map = new Map(); | 
					
						
							|  |  |  | 					for (const item of this.items) { | 
					
						
							| 
									
										
										
										
											2020-08-20 02:04:34 +08:00
										 |  |  | 						map.set(item, oldMap.get(item)); | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2020-08-20 02:04:34 +08:00
										 |  |  | 					return new PackContentItems(map); | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 				}); | 
					
						
							|  |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2020-08-20 02:04:34 +08:00
										 |  |  | 				const oldMap = value.map; | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 				/** @type {Map<string, any>} */ | 
					
						
							|  |  |  | 				const map = new Map(); | 
					
						
							|  |  |  | 				for (const item of this.items) { | 
					
						
							| 
									
										
										
										
											2020-08-20 02:04:34 +08:00
										 |  |  | 					map.set(item, oldMap.get(item)); | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2020-08-20 02:04:34 +08:00
										 |  |  | 				return new PackContentItems(map); | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-20 21:22:16 +08:00
										 |  |  | const allowCollectingMemory = buf => { | 
					
						
							|  |  |  | 	const wasted = buf.buffer.byteLength - buf.byteLength; | 
					
						
							| 
									
										
										
										
											2021-04-21 13:20:03 +08:00
										 |  |  | 	if (wasted > 8192 && (wasted > 1048576 || wasted > buf.byteLength)) { | 
					
						
							| 
									
										
										
										
											2021-04-20 21:22:16 +08:00
										 |  |  | 		return Buffer.from(buf); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return buf; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | class PackFileCacheStrategy { | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {Object} options options | 
					
						
							| 
									
										
										
										
											2020-08-14 13:27:30 +08:00
										 |  |  | 	 * @param {Compiler} options.compiler the compiler | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 	 * @param {IntermediateFileSystem} options.fs the filesystem | 
					
						
							|  |  |  | 	 * @param {string} options.context the context directory | 
					
						
							|  |  |  | 	 * @param {string} options.cacheLocation the location of the cache data | 
					
						
							|  |  |  | 	 * @param {string} options.version version identifier | 
					
						
							|  |  |  | 	 * @param {Logger} options.logger a logger | 
					
						
							| 
									
										
										
										
											2020-08-26 06:36:16 +08:00
										 |  |  | 	 * @param {SnapshotOptions} options.snapshot options regarding snapshotting | 
					
						
							| 
									
										
										
										
											2021-04-01 22:59:00 +08:00
										 |  |  | 	 * @param {number} options.maxAge max age of cache items | 
					
						
							| 
									
										
										
										
											2021-04-27 17:06:01 +08:00
										 |  |  | 	 * @param {boolean} options.profile track and log detailed timing information for individual cache items | 
					
						
							| 
									
										
										
										
											2021-04-20 21:22:16 +08:00
										 |  |  | 	 * @param {boolean} options.allowCollectingMemory allow to collect unused memory created during deserialization | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2019-08-16 17:55:10 +08:00
										 |  |  | 	constructor({ | 
					
						
							| 
									
										
										
										
											2020-08-14 13:27:30 +08:00
										 |  |  | 		compiler, | 
					
						
							| 
									
										
										
										
											2019-08-16 17:55:10 +08:00
										 |  |  | 		fs, | 
					
						
							|  |  |  | 		context, | 
					
						
							|  |  |  | 		cacheLocation, | 
					
						
							|  |  |  | 		version, | 
					
						
							|  |  |  | 		logger, | 
					
						
							| 
									
										
										
										
											2021-04-01 22:59:00 +08:00
										 |  |  | 		snapshot, | 
					
						
							| 
									
										
										
										
											2021-04-20 21:22:16 +08:00
										 |  |  | 		maxAge, | 
					
						
							| 
									
										
										
										
											2021-04-27 17:06:01 +08:00
										 |  |  | 		profile, | 
					
						
							| 
									
										
										
										
											2021-04-20 21:22:16 +08:00
										 |  |  | 		allowCollectingMemory | 
					
						
							| 
									
										
										
										
											2019-08-16 17:55:10 +08:00
										 |  |  | 	}) { | 
					
						
							| 
									
										
										
										
											2019-06-11 19:09:42 +08:00
										 |  |  | 		this.fileSerializer = createFileSerializer(fs); | 
					
						
							| 
									
										
										
										
											2019-08-16 17:55:10 +08:00
										 |  |  | 		this.fileSystemInfo = new FileSystemInfo(fs, { | 
					
						
							| 
									
										
										
										
											2020-08-26 06:36:16 +08:00
										 |  |  | 			managedPaths: snapshot.managedPaths, | 
					
						
							|  |  |  | 			immutablePaths: snapshot.immutablePaths, | 
					
						
							| 
									
										
										
										
											2019-11-05 23:47:45 +08:00
										 |  |  | 			logger: logger.getChildLogger("webpack.FileSystemInfo") | 
					
						
							| 
									
										
										
										
											2019-08-16 17:55:10 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2020-08-14 13:27:30 +08:00
										 |  |  | 		this.compiler = compiler; | 
					
						
							| 
									
										
										
										
											2019-08-13 04:59:09 +08:00
										 |  |  | 		this.context = context; | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 		this.cacheLocation = cacheLocation; | 
					
						
							| 
									
										
										
										
											2019-08-20 03:57:49 +08:00
										 |  |  | 		this.version = version; | 
					
						
							| 
									
										
										
										
											2019-08-12 19:41:23 +08:00
										 |  |  | 		this.logger = logger; | 
					
						
							| 
									
										
										
										
											2021-04-01 22:59:00 +08:00
										 |  |  | 		this.maxAge = maxAge; | 
					
						
							| 
									
										
										
										
											2021-04-27 17:06:01 +08:00
										 |  |  | 		this.profile = profile; | 
					
						
							| 
									
										
										
										
											2021-04-20 21:22:16 +08:00
										 |  |  | 		this.allowCollectingMemory = allowCollectingMemory; | 
					
						
							| 
									
										
										
										
											2020-08-26 06:36:16 +08:00
										 |  |  | 		this.snapshot = snapshot; | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 		/** @type {Set<string>} */ | 
					
						
							| 
									
										
										
										
											2019-08-20 03:57:49 +08:00
										 |  |  | 		this.buildDependencies = new Set(); | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 		/** @type {LazySet<string>} */ | 
					
						
							| 
									
										
										
										
											2019-08-20 03:57:49 +08:00
										 |  |  | 		this.newBuildDependencies = new LazySet(); | 
					
						
							| 
									
										
										
										
											2020-08-23 03:54:34 +08:00
										 |  |  | 		/** @type {Snapshot} */ | 
					
						
							| 
									
										
										
										
											2019-08-20 03:57:49 +08:00
										 |  |  | 		this.resolveBuildDependenciesSnapshot = undefined; | 
					
						
							| 
									
										
										
										
											2021-04-06 17:28:27 +08:00
										 |  |  | 		/** @type {Map<string, string | false>} */ | 
					
						
							| 
									
										
										
										
											2019-08-20 03:57:49 +08:00
										 |  |  | 		this.resolveResults = undefined; | 
					
						
							| 
									
										
										
										
											2020-08-23 03:54:34 +08:00
										 |  |  | 		/** @type {Snapshot} */ | 
					
						
							| 
									
										
										
										
											2019-08-13 22:11:40 +08:00
										 |  |  | 		this.buildSnapshot = undefined; | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 		/** @type {Promise<Pack>} */ | 
					
						
							| 
									
										
										
										
											2019-08-20 03:57:49 +08:00
										 |  |  | 		this.packPromise = this._openPack(); | 
					
						
							| 
									
										
										
										
											2021-04-01 22:59:00 +08:00
										 |  |  | 		this.storePromise = Promise.resolve(); | 
					
						
							| 
									
										
										
										
											2019-08-20 03:57:49 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-25 23:35:19 +08:00
										 |  |  | 	_getPack() { | 
					
						
							| 
									
										
										
										
											2021-04-01 22:59:00 +08:00
										 |  |  | 		if (this.packPromise === undefined) { | 
					
						
							|  |  |  | 			this.packPromise = this.storePromise.then(() => this._openPack()); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-03-25 23:35:19 +08:00
										 |  |  | 		return this.packPromise; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @returns {Promise<Pack>} the pack | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2019-08-20 03:57:49 +08:00
										 |  |  | 	_openPack() { | 
					
						
							| 
									
										
										
										
											2021-04-27 17:06:01 +08:00
										 |  |  | 		const { logger, profile, cacheLocation, version } = this; | 
					
						
							| 
									
										
										
										
											2020-08-23 03:54:34 +08:00
										 |  |  | 		/** @type {Snapshot} */ | 
					
						
							| 
									
										
										
										
											2019-08-13 22:11:40 +08:00
										 |  |  | 		let buildSnapshot; | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 		/** @type {Set<string>} */ | 
					
						
							| 
									
										
										
										
											2019-08-14 00:59:17 +08:00
										 |  |  | 		let buildDependencies; | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 		/** @type {Set<string>} */ | 
					
						
							| 
									
										
										
										
											2019-08-20 03:57:49 +08:00
										 |  |  | 		let newBuildDependencies; | 
					
						
							| 
									
										
										
										
											2020-08-23 03:54:34 +08:00
										 |  |  | 		/** @type {Snapshot} */ | 
					
						
							| 
									
										
										
										
											2019-08-20 03:57:49 +08:00
										 |  |  | 		let resolveBuildDependenciesSnapshot; | 
					
						
							| 
									
										
										
										
											2021-04-06 17:28:27 +08:00
										 |  |  | 		/** @type {Map<string, string | false>} */ | 
					
						
							| 
									
										
										
										
											2019-08-20 03:57:49 +08:00
										 |  |  | 		let resolveResults; | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		logger.time("restore cache container"); | 
					
						
							| 
									
										
										
										
											2019-08-20 03:57:49 +08:00
										 |  |  | 		return this.fileSerializer | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 			.deserialize(null, { | 
					
						
							|  |  |  | 				filename: `${cacheLocation}/index.pack`, | 
					
						
							|  |  |  | 				extension: ".pack", | 
					
						
							| 
									
										
										
										
											2021-04-20 21:22:16 +08:00
										 |  |  | 				logger, | 
					
						
							| 
									
										
										
										
											2021-04-27 17:06:01 +08:00
										 |  |  | 				profile, | 
					
						
							| 
									
										
										
										
											2021-04-20 21:22:16 +08:00
										 |  |  | 				retainedBuffer: this.allowCollectingMemory | 
					
						
							|  |  |  | 					? allowCollectingMemory | 
					
						
							|  |  |  | 					: undefined | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2019-08-20 03:57:49 +08:00
										 |  |  | 			.catch(err => { | 
					
						
							|  |  |  | 				if (err.code !== "ENOENT") { | 
					
						
							|  |  |  | 					logger.warn( | 
					
						
							|  |  |  | 						`Restoring pack failed from ${cacheLocation}.pack: ${err}` | 
					
						
							|  |  |  | 					); | 
					
						
							|  |  |  | 					logger.debug(err.stack); | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					logger.debug(`No pack exists at ${cacheLocation}.pack: ${err}`); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				return undefined; | 
					
						
							|  |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2019-08-20 18:31:36 +08:00
										 |  |  | 			.then(packContainer => { | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 				logger.timeEnd("restore cache container"); | 
					
						
							| 
									
										
										
										
											2019-08-20 18:31:36 +08:00
										 |  |  | 				if (!packContainer) return undefined; | 
					
						
							|  |  |  | 				if (!(packContainer instanceof PackContainer)) { | 
					
						
							|  |  |  | 					logger.warn( | 
					
						
							|  |  |  | 						`Restored pack from ${cacheLocation}.pack, but contained content is unexpected.`, | 
					
						
							|  |  |  | 						packContainer | 
					
						
							|  |  |  | 					); | 
					
						
							|  |  |  | 					return undefined; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if (packContainer.version !== version) { | 
					
						
							|  |  |  | 					logger.log( | 
					
						
							|  |  |  | 						`Restored pack from ${cacheLocation}.pack, but version doesn't match.` | 
					
						
							|  |  |  | 					); | 
					
						
							|  |  |  | 					return undefined; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				logger.time("check build dependencies"); | 
					
						
							|  |  |  | 				return Promise.all([ | 
					
						
							|  |  |  | 					new Promise((resolve, reject) => { | 
					
						
							|  |  |  | 						this.fileSystemInfo.checkSnapshotValid( | 
					
						
							|  |  |  | 							packContainer.buildSnapshot, | 
					
						
							|  |  |  | 							(err, valid) => { | 
					
						
							| 
									
										
										
										
											2019-08-22 16:44:48 +08:00
										 |  |  | 								if (err) { | 
					
						
							|  |  |  | 									logger.log( | 
					
						
							|  |  |  | 										`Restored pack from ${cacheLocation}.pack, but checking snapshot of build dependencies errored: ${err}.` | 
					
						
							|  |  |  | 									); | 
					
						
							|  |  |  | 									logger.debug(err.stack); | 
					
						
							|  |  |  | 									return resolve(false); | 
					
						
							|  |  |  | 								} | 
					
						
							| 
									
										
										
										
											2019-08-20 18:31:36 +08:00
										 |  |  | 								if (!valid) { | 
					
						
							|  |  |  | 									logger.log( | 
					
						
							|  |  |  | 										`Restored pack from ${cacheLocation}.pack, but build dependencies have changed.` | 
					
						
							|  |  |  | 									); | 
					
						
							|  |  |  | 									return resolve(false); | 
					
						
							|  |  |  | 								} | 
					
						
							|  |  |  | 								buildSnapshot = packContainer.buildSnapshot; | 
					
						
							|  |  |  | 								return resolve(true); | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 						); | 
					
						
							|  |  |  | 					}), | 
					
						
							|  |  |  | 					new Promise((resolve, reject) => { | 
					
						
							|  |  |  | 						this.fileSystemInfo.checkSnapshotValid( | 
					
						
							|  |  |  | 							packContainer.resolveBuildDependenciesSnapshot, | 
					
						
							|  |  |  | 							(err, valid) => { | 
					
						
							| 
									
										
										
										
											2019-08-22 16:44:48 +08:00
										 |  |  | 								if (err) { | 
					
						
							|  |  |  | 									logger.log( | 
					
						
							|  |  |  | 										`Restored pack from ${cacheLocation}.pack, but checking snapshot of resolving of build dependencies errored: ${err}.` | 
					
						
							|  |  |  | 									); | 
					
						
							|  |  |  | 									logger.debug(err.stack); | 
					
						
							|  |  |  | 									return resolve(false); | 
					
						
							|  |  |  | 								} | 
					
						
							| 
									
										
										
										
											2019-08-20 18:31:36 +08:00
										 |  |  | 								if (valid) { | 
					
						
							|  |  |  | 									resolveBuildDependenciesSnapshot = | 
					
						
							|  |  |  | 										packContainer.resolveBuildDependenciesSnapshot; | 
					
						
							|  |  |  | 									buildDependencies = packContainer.buildDependencies; | 
					
						
							|  |  |  | 									resolveResults = packContainer.resolveResults; | 
					
						
							|  |  |  | 									return resolve(true); | 
					
						
							|  |  |  | 								} | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 								logger.log( | 
					
						
							| 
									
										
										
										
											2019-08-20 18:31:36 +08:00
										 |  |  | 									"resolving of build dependencies is invalid, will re-resolve build dependencies" | 
					
						
							|  |  |  | 								); | 
					
						
							|  |  |  | 								this.fileSystemInfo.checkResolveResultsValid( | 
					
						
							|  |  |  | 									packContainer.resolveResults, | 
					
						
							|  |  |  | 									(err, valid) => { | 
					
						
							| 
									
										
										
										
											2019-08-22 16:44:48 +08:00
										 |  |  | 										if (err) { | 
					
						
							|  |  |  | 											logger.log( | 
					
						
							|  |  |  | 												`Restored pack from ${cacheLocation}.pack, but resolving of build dependencies errored: ${err}.` | 
					
						
							|  |  |  | 											); | 
					
						
							|  |  |  | 											logger.debug(err.stack); | 
					
						
							|  |  |  | 											return resolve(false); | 
					
						
							|  |  |  | 										} | 
					
						
							| 
									
										
										
										
											2019-08-20 18:31:36 +08:00
										 |  |  | 										if (valid) { | 
					
						
							|  |  |  | 											newBuildDependencies = packContainer.buildDependencies; | 
					
						
							|  |  |  | 											resolveResults = packContainer.resolveResults; | 
					
						
							|  |  |  | 											return resolve(true); | 
					
						
							|  |  |  | 										} | 
					
						
							| 
									
										
										
										
											2019-08-20 03:57:49 +08:00
										 |  |  | 										logger.log( | 
					
						
							| 
									
										
										
										
											2019-08-20 18:31:36 +08:00
										 |  |  | 											`Restored pack from ${cacheLocation}.pack, but build dependencies resolve to different locations.` | 
					
						
							| 
									
										
										
										
											2019-08-20 03:57:49 +08:00
										 |  |  | 										); | 
					
						
							|  |  |  | 										return resolve(false); | 
					
						
							|  |  |  | 									} | 
					
						
							| 
									
										
										
										
											2019-08-20 18:31:36 +08:00
										 |  |  | 								); | 
					
						
							| 
									
										
										
										
											2019-08-13 04:59:09 +08:00
										 |  |  | 							} | 
					
						
							| 
									
										
										
										
											2019-08-13 22:11:40 +08:00
										 |  |  | 						); | 
					
						
							| 
									
										
										
										
											2019-08-20 18:31:36 +08:00
										 |  |  | 					}) | 
					
						
							|  |  |  | 				]) | 
					
						
							|  |  |  | 					.catch(err => { | 
					
						
							|  |  |  | 						logger.timeEnd("check build dependencies"); | 
					
						
							|  |  |  | 						throw err; | 
					
						
							|  |  |  | 					}) | 
					
						
							|  |  |  | 					.then(([buildSnapshotValid, resolveValid]) => { | 
					
						
							|  |  |  | 						logger.timeEnd("check build dependencies"); | 
					
						
							|  |  |  | 						if (buildSnapshotValid && resolveValid) { | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 							logger.time("restore cache content metadata"); | 
					
						
							|  |  |  | 							const d = packContainer.data(); | 
					
						
							|  |  |  | 							logger.timeEnd("restore cache content metadata"); | 
					
						
							|  |  |  | 							return d; | 
					
						
							| 
									
										
										
										
											2019-08-20 18:31:36 +08:00
										 |  |  | 						} | 
					
						
							|  |  |  | 						return undefined; | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 			.then(pack => { | 
					
						
							|  |  |  | 				if (pack) { | 
					
						
							| 
									
										
										
										
											2021-04-01 22:59:00 +08:00
										 |  |  | 					pack.maxAge = this.maxAge; | 
					
						
							| 
									
										
										
										
											2019-08-13 22:11:40 +08:00
										 |  |  | 					this.buildSnapshot = buildSnapshot; | 
					
						
							| 
									
										
										
										
											2019-08-20 03:57:49 +08:00
										 |  |  | 					if (buildDependencies) this.buildDependencies = buildDependencies; | 
					
						
							|  |  |  | 					if (newBuildDependencies) | 
					
						
							|  |  |  | 						this.newBuildDependencies.addAll(newBuildDependencies); | 
					
						
							|  |  |  | 					this.resolveResults = resolveResults; | 
					
						
							|  |  |  | 					this.resolveBuildDependenciesSnapshot = resolveBuildDependenciesSnapshot; | 
					
						
							| 
									
										
										
										
											2019-08-20 18:31:36 +08:00
										 |  |  | 					return pack; | 
					
						
							| 
									
										
										
										
											2019-08-13 22:11:40 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2021-04-01 22:59:00 +08:00
										 |  |  | 				return new Pack(logger, this.maxAge); | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 			.catch(err => { | 
					
						
							|  |  |  | 				this.logger.warn( | 
					
						
							|  |  |  | 					`Restoring pack from ${cacheLocation}.pack failed: ${err}` | 
					
						
							|  |  |  | 				); | 
					
						
							|  |  |  | 				this.logger.debug(err.stack); | 
					
						
							| 
									
										
										
										
											2021-04-01 22:59:00 +08:00
										 |  |  | 				return new Pack(logger, this.maxAge); | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 			}); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-12 20:55:13 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {string} identifier unique name for the resource | 
					
						
							|  |  |  | 	 * @param {Etag | null} etag etag of the resource | 
					
						
							|  |  |  | 	 * @param {any} data cached content | 
					
						
							|  |  |  | 	 * @returns {Promise<void>} promise | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	store(identifier, etag, data) { | 
					
						
							| 
									
										
										
										
											2021-03-25 23:35:19 +08:00
										 |  |  | 		return this._getPack().then(pack => { | 
					
						
							| 
									
										
										
										
											2019-11-12 20:55:13 +08:00
										 |  |  | 			pack.set(identifier, etag === null ? null : etag.toString(), data); | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 		}); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-12 20:55:13 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {string} identifier unique name for the resource | 
					
						
							|  |  |  | 	 * @param {Etag | null} etag etag of the resource | 
					
						
							|  |  |  | 	 * @returns {Promise<any>} promise to the cached content | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 	restore(identifier, etag) { | 
					
						
							| 
									
										
										
										
											2021-03-25 23:35:19 +08:00
										 |  |  | 		return this._getPack() | 
					
						
							| 
									
										
										
										
											2019-11-12 20:55:13 +08:00
										 |  |  | 			.then(pack => | 
					
						
							|  |  |  | 				pack.get(identifier, etag === null ? null : etag.toString()) | 
					
						
							|  |  |  | 			) | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 			.catch(err => { | 
					
						
							| 
									
										
										
										
											2019-08-12 19:41:23 +08:00
										 |  |  | 				if (err && err.code !== "ENOENT") { | 
					
						
							|  |  |  | 					this.logger.warn( | 
					
						
							|  |  |  | 						`Restoring failed for ${identifier} from pack: ${err}` | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 					); | 
					
						
							| 
									
										
										
										
											2019-08-12 19:41:23 +08:00
										 |  |  | 					this.logger.debug(err.stack); | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-13 04:59:09 +08:00
										 |  |  | 	storeBuildDependencies(dependencies) { | 
					
						
							| 
									
										
										
										
											2019-08-20 03:57:49 +08:00
										 |  |  | 		this.newBuildDependencies.addAll(dependencies); | 
					
						
							| 
									
										
										
										
											2019-08-14 00:59:17 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-13 04:59:09 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-14 00:59:17 +08:00
										 |  |  | 	afterAllStored() { | 
					
						
							| 
									
										
										
										
											2021-04-01 22:59:00 +08:00
										 |  |  | 		const packPromise = this.packPromise; | 
					
						
							|  |  |  | 		if (packPromise === undefined) return Promise.resolve(); | 
					
						
							| 
									
										
										
										
											2020-08-14 13:27:30 +08:00
										 |  |  | 		const reportProgress = ProgressPlugin.getReporter(this.compiler); | 
					
						
							| 
									
										
										
										
											2021-04-01 22:59:00 +08:00
										 |  |  | 		this.packPromise = undefined; | 
					
						
							|  |  |  | 		return (this.storePromise = packPromise | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 			.then(pack => { | 
					
						
							|  |  |  | 				if (!pack.invalid) return; | 
					
						
							|  |  |  | 				this.logger.log(`Storing pack...`); | 
					
						
							|  |  |  | 				let promise; | 
					
						
							|  |  |  | 				const newBuildDependencies = new Set(); | 
					
						
							|  |  |  | 				for (const dep of this.newBuildDependencies) { | 
					
						
							|  |  |  | 					if (!this.buildDependencies.has(dep)) { | 
					
						
							|  |  |  | 						newBuildDependencies.add(dep); | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2019-08-14 00:59:17 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 				if (newBuildDependencies.size > 0 || !this.buildSnapshot) { | 
					
						
							| 
									
										
										
										
											2020-08-14 13:27:30 +08:00
										 |  |  | 					if (reportProgress) reportProgress(0.5, "resolve build dependencies"); | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 					this.logger.debug( | 
					
						
							|  |  |  | 						`Capturing build dependencies... (${Array.from( | 
					
						
							|  |  |  | 							newBuildDependencies | 
					
						
							|  |  |  | 						).join(", ")})`
 | 
					
						
							|  |  |  | 					); | 
					
						
							|  |  |  | 					promise = new Promise((resolve, reject) => { | 
					
						
							|  |  |  | 						this.logger.time("resolve build dependencies"); | 
					
						
							|  |  |  | 						this.fileSystemInfo.resolveBuildDependencies( | 
					
						
							|  |  |  | 							this.context, | 
					
						
							|  |  |  | 							newBuildDependencies, | 
					
						
							|  |  |  | 							(err, result) => { | 
					
						
							|  |  |  | 								this.logger.timeEnd("resolve build dependencies"); | 
					
						
							|  |  |  | 								if (err) return reject(err); | 
					
						
							| 
									
										
										
										
											2019-08-14 00:59:17 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 								this.logger.time("snapshot build dependencies"); | 
					
						
							|  |  |  | 								const { | 
					
						
							|  |  |  | 									files, | 
					
						
							|  |  |  | 									directories, | 
					
						
							|  |  |  | 									missing, | 
					
						
							|  |  |  | 									resolveResults, | 
					
						
							|  |  |  | 									resolveDependencies | 
					
						
							|  |  |  | 								} = result; | 
					
						
							|  |  |  | 								if (this.resolveResults) { | 
					
						
							|  |  |  | 									for (const [key, value] of resolveResults) { | 
					
						
							|  |  |  | 										this.resolveResults.set(key, value); | 
					
						
							| 
									
										
										
										
											2019-08-20 03:57:49 +08:00
										 |  |  | 									} | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 								} else { | 
					
						
							|  |  |  | 									this.resolveResults = resolveResults; | 
					
						
							|  |  |  | 								} | 
					
						
							| 
									
										
										
										
											2020-08-26 06:36:16 +08:00
										 |  |  | 								if (reportProgress) { | 
					
						
							| 
									
										
										
										
											2020-08-14 13:27:30 +08:00
										 |  |  | 									reportProgress( | 
					
						
							|  |  |  | 										0.6, | 
					
						
							| 
									
										
										
										
											2020-08-26 06:36:16 +08:00
										 |  |  | 										"snapshot build dependencies", | 
					
						
							|  |  |  | 										"resolving" | 
					
						
							| 
									
										
										
										
											2020-08-14 13:27:30 +08:00
										 |  |  | 									); | 
					
						
							| 
									
										
										
										
											2020-08-26 06:36:16 +08:00
										 |  |  | 								} | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 								this.fileSystemInfo.createSnapshot( | 
					
						
							|  |  |  | 									undefined, | 
					
						
							|  |  |  | 									resolveDependencies.files, | 
					
						
							|  |  |  | 									resolveDependencies.directories, | 
					
						
							|  |  |  | 									resolveDependencies.missing, | 
					
						
							| 
									
										
										
										
											2020-08-26 06:36:16 +08:00
										 |  |  | 									this.snapshot.resolveBuildDependencies, | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 									(err, snapshot) => { | 
					
						
							|  |  |  | 										if (err) { | 
					
						
							| 
									
										
										
										
											2019-08-20 03:57:49 +08:00
										 |  |  | 											this.logger.timeEnd("snapshot build dependencies"); | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 											return reject(err); | 
					
						
							|  |  |  | 										} | 
					
						
							| 
									
										
										
										
											2020-01-28 21:01:19 +08:00
										 |  |  | 										if (!snapshot) { | 
					
						
							|  |  |  | 											this.logger.timeEnd("snapshot build dependencies"); | 
					
						
							|  |  |  | 											return reject( | 
					
						
							|  |  |  | 												new Error("Unable to snapshot resolve dependencies") | 
					
						
							|  |  |  | 											); | 
					
						
							|  |  |  | 										} | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 										if (this.resolveBuildDependenciesSnapshot) { | 
					
						
							|  |  |  | 											this.resolveBuildDependenciesSnapshot = this.fileSystemInfo.mergeSnapshots( | 
					
						
							|  |  |  | 												this.resolveBuildDependenciesSnapshot, | 
					
						
							|  |  |  | 												snapshot | 
					
						
							|  |  |  | 											); | 
					
						
							|  |  |  | 										} else { | 
					
						
							|  |  |  | 											this.resolveBuildDependenciesSnapshot = snapshot; | 
					
						
							|  |  |  | 										} | 
					
						
							| 
									
										
										
										
											2020-08-26 06:36:16 +08:00
										 |  |  | 										if (reportProgress) { | 
					
						
							| 
									
										
										
										
											2020-08-14 13:27:30 +08:00
										 |  |  | 											reportProgress( | 
					
						
							|  |  |  | 												0.7, | 
					
						
							| 
									
										
										
										
											2020-08-26 06:36:16 +08:00
										 |  |  | 												"snapshot build dependencies", | 
					
						
							|  |  |  | 												"modules" | 
					
						
							| 
									
										
										
										
											2020-08-14 13:27:30 +08:00
										 |  |  | 											); | 
					
						
							| 
									
										
										
										
											2020-08-26 06:36:16 +08:00
										 |  |  | 										} | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 										this.fileSystemInfo.createSnapshot( | 
					
						
							|  |  |  | 											undefined, | 
					
						
							|  |  |  | 											files, | 
					
						
							|  |  |  | 											directories, | 
					
						
							|  |  |  | 											missing, | 
					
						
							| 
									
										
										
										
											2020-08-26 06:36:16 +08:00
										 |  |  | 											this.snapshot.buildDependencies, | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 											(err, snapshot) => { | 
					
						
							|  |  |  | 												this.logger.timeEnd("snapshot build dependencies"); | 
					
						
							|  |  |  | 												if (err) return reject(err); | 
					
						
							| 
									
										
										
										
											2020-01-28 21:01:19 +08:00
										 |  |  | 												if (!snapshot) { | 
					
						
							|  |  |  | 													return reject( | 
					
						
							|  |  |  | 														new Error("Unable to snapshot build dependencies") | 
					
						
							|  |  |  | 													); | 
					
						
							|  |  |  | 												} | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 												this.logger.debug("Captured build dependencies"); | 
					
						
							| 
									
										
										
										
											2019-08-14 00:59:17 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 												if (this.buildSnapshot) { | 
					
						
							|  |  |  | 													this.buildSnapshot = this.fileSystemInfo.mergeSnapshots( | 
					
						
							|  |  |  | 														this.buildSnapshot, | 
					
						
							|  |  |  | 														snapshot | 
					
						
							|  |  |  | 													); | 
					
						
							|  |  |  | 												} else { | 
					
						
							|  |  |  | 													this.buildSnapshot = snapshot; | 
					
						
							|  |  |  | 												} | 
					
						
							| 
									
										
										
										
											2019-08-20 03:57:49 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 												resolve(); | 
					
						
							|  |  |  | 											} | 
					
						
							|  |  |  | 										); | 
					
						
							|  |  |  | 									} | 
					
						
							|  |  |  | 								); | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 						); | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					promise = Promise.resolve(); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				return promise.then(() => { | 
					
						
							| 
									
										
										
										
											2020-08-14 13:27:30 +08:00
										 |  |  | 					if (reportProgress) reportProgress(0.8, "serialize pack"); | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 					this.logger.time(`store pack`); | 
					
						
							| 
									
										
										
										
											2021-01-14 03:37:45 +08:00
										 |  |  | 					const updatedBuildDependencies = new Set(this.buildDependencies); | 
					
						
							|  |  |  | 					for (const dep of newBuildDependencies) { | 
					
						
							|  |  |  | 						updatedBuildDependencies.add(dep); | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 					const content = new PackContainer( | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 						pack, | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 						this.version, | 
					
						
							|  |  |  | 						this.buildSnapshot, | 
					
						
							| 
									
										
										
										
											2021-01-14 03:37:45 +08:00
										 |  |  | 						updatedBuildDependencies, | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 						this.resolveResults, | 
					
						
							|  |  |  | 						this.resolveBuildDependenciesSnapshot | 
					
						
							| 
									
										
										
										
											2019-08-13 04:59:09 +08:00
										 |  |  | 					); | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 					return this.fileSerializer | 
					
						
							|  |  |  | 						.serialize(content, { | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 							filename: `${this.cacheLocation}/index.pack`, | 
					
						
							|  |  |  | 							extension: ".pack", | 
					
						
							| 
									
										
										
										
											2021-04-27 17:06:01 +08:00
										 |  |  | 							logger: this.logger, | 
					
						
							|  |  |  | 							profile: this.profile | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 						}) | 
					
						
							|  |  |  | 						.then(() => { | 
					
						
							| 
									
										
										
										
											2020-12-15 23:58:40 +08:00
										 |  |  | 							for (const dep of newBuildDependencies) { | 
					
						
							|  |  |  | 								this.buildDependencies.add(dep); | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 							this.newBuildDependencies.clear(); | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 							this.logger.timeEnd(`store pack`); | 
					
						
							| 
									
										
										
										
											2021-04-01 22:59:00 +08:00
										 |  |  | 							const stats = pack.getContentStats(); | 
					
						
							|  |  |  | 							this.logger.log( | 
					
						
							|  |  |  | 								"Stored pack (%d items, %d files, %d MiB)", | 
					
						
							|  |  |  | 								pack.itemInfo.size, | 
					
						
							|  |  |  | 								stats.count, | 
					
						
							|  |  |  | 								Math.round(stats.size / 1024 / 1024) | 
					
						
							|  |  |  | 							); | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 						}) | 
					
						
							|  |  |  | 						.catch(err => { | 
					
						
							|  |  |  | 							this.logger.timeEnd(`store pack`); | 
					
						
							|  |  |  | 							this.logger.warn(`Caching failed for pack: ${err}`); | 
					
						
							|  |  |  | 							this.logger.debug(err.stack); | 
					
						
							|  |  |  | 						}); | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 				}); | 
					
						
							| 
									
										
										
										
											2019-09-04 19:34:34 +08:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 			.catch(err => { | 
					
						
							|  |  |  | 				this.logger.warn(`Caching failed for pack: ${err}`); | 
					
						
							|  |  |  | 				this.logger.debug(err.stack); | 
					
						
							| 
									
										
										
										
											2021-04-01 22:59:00 +08:00
										 |  |  | 			})); | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-03-25 23:35:19 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	clear() { | 
					
						
							|  |  |  | 		this.fileSystemInfo.clear(); | 
					
						
							|  |  |  | 		this.buildDependencies.clear(); | 
					
						
							|  |  |  | 		this.newBuildDependencies.clear(); | 
					
						
							|  |  |  | 		this.resolveBuildDependenciesSnapshot = undefined; | 
					
						
							|  |  |  | 		this.resolveResults = undefined; | 
					
						
							|  |  |  | 		this.buildSnapshot = undefined; | 
					
						
							|  |  |  | 		this.packPromise = undefined; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-01-26 02:21:45 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module.exports = PackFileCacheStrategy; |