| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | 	Author Tobias Koppers @sokra | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | "use strict"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-23 17:31:20 +08:00
										 |  |  | const fs = require("fs"); | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | const path = require("path"); | 
					
						
							|  |  |  | const createHash = require("../util/createHash"); | 
					
						
							| 
									
										
										
										
											2018-10-23 17:31:20 +08:00
										 |  |  | const makeSerializable = require("../util/makeSerializable"); | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | const serializer = require("../util/serializer"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** @typedef {import("webpack-sources").Source} Source */ | 
					
						
							|  |  |  | /** @typedef {import("../../declarations/WebpackOptions").FileCacheOptions} FileCacheOptions */ | 
					
						
							|  |  |  | /** @typedef {import("../Compiler")} Compiler */ | 
					
						
							|  |  |  | /** @typedef {import("../Module")} Module */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-23 17:31:20 +08:00
										 |  |  | class Pack { | 
					
						
							|  |  |  | 	constructor(version) { | 
					
						
							|  |  |  | 		this.version = version; | 
					
						
							|  |  |  | 		this.content = new Map(); | 
					
						
							|  |  |  | 		this.lastAccess = new Map(); | 
					
						
							|  |  |  | 		this.used = new Set(); | 
					
						
							|  |  |  | 		this.invalid = false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	get(relativeFilename) { | 
					
						
							|  |  |  | 		this.used.add(relativeFilename); | 
					
						
							|  |  |  | 		return this.content.get(relativeFilename); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	set(relativeFilename, data) { | 
					
						
							|  |  |  | 		this.used.add(relativeFilename); | 
					
						
							|  |  |  | 		this.invalid = true; | 
					
						
							|  |  |  | 		return this.content.set(relativeFilename, data); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	collectGarbage(maxAge) { | 
					
						
							|  |  |  | 		this._updateLastAccess(); | 
					
						
							|  |  |  | 		const now = Date.now(); | 
					
						
							|  |  |  | 		for (const [relativeFilename, lastAccess] of this.lastAccess) { | 
					
						
							|  |  |  | 			if (now - lastAccess > maxAge) { | 
					
						
							|  |  |  | 				this.lastAccess.delete(relativeFilename); | 
					
						
							|  |  |  | 				this.content.delete(relativeFilename); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	_updateLastAccess() { | 
					
						
							|  |  |  | 		const now = Date.now(); | 
					
						
							|  |  |  | 		for (const relativeFilename of this.used) { | 
					
						
							|  |  |  | 			this.lastAccess.set(relativeFilename, now); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		this.used.clear(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	serialize({ write, snapshot, rollback }) { | 
					
						
							|  |  |  | 		this._updateLastAccess(); | 
					
						
							|  |  |  | 		write(this.version); | 
					
						
							|  |  |  | 		for (const [relativeFilename, data] of this.content) { | 
					
						
							|  |  |  | 			const s = snapshot(); | 
					
						
							|  |  |  | 			try { | 
					
						
							|  |  |  | 				write(relativeFilename); | 
					
						
							|  |  |  | 				write(data); | 
					
						
							|  |  |  | 			} catch (err) { | 
					
						
							|  |  |  | 				rollback(s); | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		write(null); | 
					
						
							|  |  |  | 		write(this.lastAccess); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	deserialize({ read }) { | 
					
						
							|  |  |  | 		this.version = read(); | 
					
						
							|  |  |  | 		this.content = new Map(); | 
					
						
							|  |  |  | 		let relativeFilename = read(); | 
					
						
							|  |  |  | 		while (relativeFilename !== null) { | 
					
						
							|  |  |  | 			this.content.set(relativeFilename, read()); | 
					
						
							|  |  |  | 			relativeFilename = read(); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		this.lastAccess = read(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | makeSerializable(Pack, "webpack/lib/cache/FileCachePlugin", "Pack"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | const memorize = fn => { | 
					
						
							|  |  |  | 	let result = undefined; | 
					
						
							|  |  |  | 	return () => { | 
					
						
							|  |  |  | 		if (result === undefined) result = fn(); | 
					
						
							|  |  |  | 		return result; | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const memoryCache = new Map(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class FileCachePlugin { | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {FileCacheOptions} options options | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	constructor(options) { | 
					
						
							|  |  |  | 		this.options = options; | 
					
						
							| 
									
										
										
										
											2018-10-31 18:15:59 +08:00
										 |  |  | 		this.directMemoryCache = new Map(); | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-18 04:15:46 +08:00
										 |  |  | 	static purgeMemoryCache() { | 
					
						
							|  |  |  | 		memoryCache.clear(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {Compiler} compiler Webpack compiler | 
					
						
							|  |  |  | 	 * @returns {void} | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	apply(compiler) { | 
					
						
							|  |  |  | 		const cacheDirectory = path.resolve( | 
					
						
							|  |  |  | 			this.options.cacheDirectory || "node_modules/.cache/webpack/", | 
					
						
							| 
									
										
										
										
											2018-10-10 16:07:51 +08:00
										 |  |  | 			this.options.name || "default" | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 		); | 
					
						
							|  |  |  | 		const hashAlgorithm = this.options.hashAlgorithm || "md4"; | 
					
						
							|  |  |  | 		const version = this.options.version || ""; | 
					
						
							| 
									
										
										
										
											2018-10-10 16:51:08 +08:00
										 |  |  | 		const log = this.options.loglevel | 
					
						
							| 
									
										
										
										
											2018-10-23 13:33:45 +08:00
										 |  |  | 			? { debug: 4, verbose: 3, info: 2, warning: 1 }[this.options.loglevel] | 
					
						
							| 
									
										
										
										
											2018-10-10 16:51:08 +08:00
										 |  |  | 			: 0; | 
					
						
							| 
									
										
										
										
											2018-10-29 19:06:21 +08:00
										 |  |  | 		const store = this.options.store || "pack"; | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		let pendingPromiseFactories = new Map(); | 
					
						
							|  |  |  | 		const toHash = str => { | 
					
						
							|  |  |  | 			const hash = createHash(hashAlgorithm); | 
					
						
							|  |  |  | 			hash.update(str); | 
					
						
							|  |  |  | 			const digest = hash.digest("hex"); | 
					
						
							|  |  |  | 			return `${digest.slice(0, 2)}/${digest.slice(2)}`; | 
					
						
							|  |  |  | 		}; | 
					
						
							| 
									
										
										
										
											2018-10-23 17:31:20 +08:00
										 |  |  | 		let packPromise; | 
					
						
							|  |  |  | 		if (store === "pack") { | 
					
						
							|  |  |  | 			packPromise = serializer | 
					
						
							|  |  |  | 				.deserializeFromFile(`${cacheDirectory}.pack`) | 
					
						
							|  |  |  | 				.then(cacheEntry => { | 
					
						
							|  |  |  | 					if (cacheEntry) { | 
					
						
							|  |  |  | 						if (!(cacheEntry instanceof Pack)) { | 
					
						
							| 
									
										
										
										
											2018-10-23 13:33:45 +08:00
										 |  |  | 							if (log >= 3) { | 
					
						
							| 
									
										
										
										
											2018-10-23 17:31:20 +08:00
										 |  |  | 								console.warn( | 
					
						
							|  |  |  | 									`Restored pack from ${cacheDirectory}.pack, but is not a Pack.` | 
					
						
							|  |  |  | 								); | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 							} | 
					
						
							| 
									
										
										
										
											2018-10-23 17:31:20 +08:00
										 |  |  | 							return new Pack(version); | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						if (cacheEntry.version !== version) { | 
					
						
							| 
									
										
										
										
											2018-10-23 13:33:45 +08:00
										 |  |  | 							if (log >= 3) { | 
					
						
							| 
									
										
										
										
											2018-10-10 23:19:31 +08:00
										 |  |  | 								console.warn( | 
					
						
							| 
									
										
										
										
											2018-10-23 17:31:20 +08:00
										 |  |  | 									`Restored pack from ${cacheDirectory}.pack, but version doesn't match.` | 
					
						
							| 
									
										
										
										
											2018-10-10 23:19:31 +08:00
										 |  |  | 								); | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 							} | 
					
						
							| 
									
										
										
										
											2018-10-23 17:31:20 +08:00
										 |  |  | 							return new Pack(version); | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						return cacheEntry; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					return new Pack(version); | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 				.catch(err => { | 
					
						
							|  |  |  | 					if (log >= 1 && err && err.code !== "ENOENT") { | 
					
						
							|  |  |  | 						console.warn( | 
					
						
							|  |  |  | 							`Restoring pack failed from ${cacheDirectory}.pack: ${ | 
					
						
							| 
									
										
										
										
											2018-10-23 13:33:45 +08:00
										 |  |  | 								log >= 4 ? err.stack : err | 
					
						
							| 
									
										
										
										
											2018-10-23 17:31:20 +08:00
										 |  |  | 							}`
 | 
					
						
							|  |  |  | 						); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					return new Pack(version); | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		compiler.cache.hooks.store.tapPromise( | 
					
						
							|  |  |  | 			"FileCachePlugin", | 
					
						
							|  |  |  | 			(identifier, etag, data) => { | 
					
						
							|  |  |  | 				const entry = { | 
					
						
							|  |  |  | 					identifier, | 
					
						
							| 
									
										
										
										
											2018-10-29 19:07:02 +08:00
										 |  |  | 					data: etag ? () => data : data, | 
					
						
							| 
									
										
										
										
											2018-10-23 17:31:20 +08:00
										 |  |  | 					etag, | 
					
						
							|  |  |  | 					version | 
					
						
							|  |  |  | 				}; | 
					
						
							|  |  |  | 				const relativeFilename = toHash(identifier) + ".data"; | 
					
						
							|  |  |  | 				const filename = path.join(cacheDirectory, relativeFilename); | 
					
						
							| 
									
										
										
										
											2018-10-31 18:15:59 +08:00
										 |  |  | 				this.directMemoryCache.set(identifier, entry); | 
					
						
							| 
									
										
										
										
											2018-10-23 17:31:20 +08:00
										 |  |  | 				memoryCache.set(filename, entry); | 
					
						
							|  |  |  | 				const promiseFactory = | 
					
						
							|  |  |  | 					store === "pack" | 
					
						
							|  |  |  | 						? () => | 
					
						
							|  |  |  | 								packPromise.then(pack => { | 
					
						
							|  |  |  | 									if (log >= 2) { | 
					
						
							|  |  |  | 										console.warn(`Cached ${identifier} to pack.`); | 
					
						
							|  |  |  | 									} | 
					
						
							|  |  |  | 									pack.set(relativeFilename, entry); | 
					
						
							|  |  |  | 								}) | 
					
						
							|  |  |  | 						: () => | 
					
						
							|  |  |  | 								serializer | 
					
						
							|  |  |  | 									.serializeToFile(entry, filename) | 
					
						
							|  |  |  | 									.then(() => { | 
					
						
							|  |  |  | 										if (log >= 2) { | 
					
						
							|  |  |  | 											console.warn(`Cached ${identifier} to ${filename}.`); | 
					
						
							|  |  |  | 										} | 
					
						
							|  |  |  | 									}) | 
					
						
							|  |  |  | 									.catch(err => { | 
					
						
							|  |  |  | 										if (log >= 1) { | 
					
						
							|  |  |  | 											console.warn( | 
					
						
							|  |  |  | 												`Caching failed for ${identifier}: ${ | 
					
						
							|  |  |  | 													log >= 3 ? err.stack : err | 
					
						
							|  |  |  | 												}`
 | 
					
						
							|  |  |  | 											); | 
					
						
							|  |  |  | 										} | 
					
						
							|  |  |  | 									}); | 
					
						
							|  |  |  | 				if (store === "instant" || store === "pack") { | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 					return promiseFactory(); | 
					
						
							|  |  |  | 				} else if (store === "idle") { | 
					
						
							|  |  |  | 					pendingPromiseFactories.set(filename, promiseFactory); | 
					
						
							|  |  |  | 					return Promise.resolve(); | 
					
						
							|  |  |  | 				} else if (store === "background") { | 
					
						
							|  |  |  | 					const promise = promiseFactory(); | 
					
						
							|  |  |  | 					pendingPromiseFactories.set(filename, () => promise); | 
					
						
							|  |  |  | 					return Promise.resolve(); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		); | 
					
						
							|  |  |  | 		compiler.cache.hooks.get.tapPromise( | 
					
						
							|  |  |  | 			"FileCachePlugin", | 
					
						
							|  |  |  | 			(identifier, etag) => { | 
					
						
							| 
									
										
										
										
											2018-10-31 18:15:59 +08:00
										 |  |  | 				const directMemory = this.directMemoryCache.get(identifier); | 
					
						
							|  |  |  | 				if (directMemory !== undefined) { | 
					
						
							|  |  |  | 					return Promise.resolve( | 
					
						
							|  |  |  | 						directMemory.etag !== etag | 
					
						
							|  |  |  | 							? undefined | 
					
						
							|  |  |  | 							: typeof directMemory.data === "function" | 
					
						
							|  |  |  | 								? directMemory.data() | 
					
						
							|  |  |  | 								: directMemory.data | 
					
						
							|  |  |  | 					); | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-10-23 17:31:20 +08:00
										 |  |  | 				const relativeFilename = toHash(identifier) + ".data"; | 
					
						
							|  |  |  | 				const filename = path.join(cacheDirectory, relativeFilename); | 
					
						
							|  |  |  | 				const logMessage = store === "pack" ? "pack" : filename; | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 				const memory = memoryCache.get(filename); | 
					
						
							|  |  |  | 				if (memory !== undefined) { | 
					
						
							|  |  |  | 					return Promise.resolve( | 
					
						
							| 
									
										
										
										
											2018-10-23 17:31:20 +08:00
										 |  |  | 						memory.etag !== etag || memory.version !== version | 
					
						
							|  |  |  | 							? undefined | 
					
						
							|  |  |  | 							: typeof memory.data === "function" | 
					
						
							|  |  |  | 								? memory.data() | 
					
						
							|  |  |  | 								: memory.data | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 					); | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-10-23 17:31:20 +08:00
										 |  |  | 				const cacheEntryPromise = | 
					
						
							|  |  |  | 					store === "pack" | 
					
						
							|  |  |  | 						? packPromise.then(pack => pack.get(relativeFilename)) | 
					
						
							|  |  |  | 						: serializer.deserializeFromFile(filename); | 
					
						
							|  |  |  | 				return cacheEntryPromise.then( | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 					cacheEntry => { | 
					
						
							| 
									
										
										
										
											2018-10-23 17:31:20 +08:00
										 |  |  | 						if (cacheEntry === undefined) return; | 
					
						
							|  |  |  | 						if (typeof cacheEntry.data === "function") | 
					
						
							|  |  |  | 							cacheEntry.data = memorize(cacheEntry.data); | 
					
						
							| 
									
										
										
										
											2018-10-31 18:15:59 +08:00
										 |  |  | 						this.directMemoryCache.set(identifier, cacheEntry); | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 						memoryCache.set(filename, cacheEntry); | 
					
						
							|  |  |  | 						if (cacheEntry === undefined) return; | 
					
						
							|  |  |  | 						if (cacheEntry.identifier !== identifier) { | 
					
						
							| 
									
										
										
										
											2018-10-23 13:33:45 +08:00
										 |  |  | 							if (log >= 3) { | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 								console.warn( | 
					
						
							| 
									
										
										
										
											2018-10-23 17:31:20 +08:00
										 |  |  | 									`Restored ${identifier} from ${logMessage}, but identifier doesn't match.` | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 								); | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 							return; | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						if (cacheEntry.etag !== etag) { | 
					
						
							| 
									
										
										
										
											2018-10-23 13:33:45 +08:00
										 |  |  | 							if (log >= 3) { | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 								console.warn( | 
					
						
							| 
									
										
										
										
											2018-10-23 17:31:20 +08:00
										 |  |  | 									`Restored ${identifier} from ${logMessage}, but etag doesn't match.` | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 								); | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 							return; | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						if (cacheEntry.version !== version) { | 
					
						
							| 
									
										
										
										
											2018-10-23 13:33:45 +08:00
										 |  |  | 							if (log >= 3) { | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 								console.warn( | 
					
						
							| 
									
										
										
										
											2018-10-23 17:31:20 +08:00
										 |  |  | 									`Restored ${identifier} from ${logMessage}, but version doesn't match.` | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 								); | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 							return; | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2018-10-23 13:33:45 +08:00
										 |  |  | 						if (log >= 3) { | 
					
						
							| 
									
										
										
										
											2018-10-23 17:31:20 +08:00
										 |  |  | 							console.warn(`Restored ${identifier} from ${logMessage}.`); | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 						} | 
					
						
							| 
									
										
										
										
											2018-10-23 17:31:20 +08:00
										 |  |  | 						if (typeof cacheEntry.data === "function") return cacheEntry.data(); | 
					
						
							|  |  |  | 						return cacheEntry.data; | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 					}, | 
					
						
							|  |  |  | 					err => { | 
					
						
							| 
									
										
										
										
											2018-10-10 16:51:08 +08:00
										 |  |  | 						if (log >= 1 && err && err.code !== "ENOENT") { | 
					
						
							| 
									
										
										
										
											2018-10-10 15:51:41 +08:00
										 |  |  | 							console.warn( | 
					
						
							| 
									
										
										
										
											2018-10-23 17:31:20 +08:00
										 |  |  | 								`Restoring failed for ${identifier} from ${logMessage}: ${ | 
					
						
							| 
									
										
										
										
											2018-10-23 13:33:45 +08:00
										 |  |  | 									log >= 4 ? err.stack : err | 
					
						
							| 
									
										
										
										
											2018-10-10 15:51:41 +08:00
										 |  |  | 								}`
 | 
					
						
							|  |  |  | 							); | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		); | 
					
						
							| 
									
										
										
										
											2018-10-23 17:31:20 +08:00
										 |  |  | 		const serializePack = () => { | 
					
						
							|  |  |  | 			packPromise = packPromise.then(pack => { | 
					
						
							|  |  |  | 				if (!pack.invalid) return pack; | 
					
						
							|  |  |  | 				if (log >= 3) { | 
					
						
							|  |  |  | 					console.warn(`Storing pack...`); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				pack.collectGarbage(1000 * 60 * 60 * 24 * 2); | 
					
						
							|  |  |  | 				return serializer | 
					
						
							|  |  |  | 					.serializeToFile(pack, `${cacheDirectory}.pack~`) | 
					
						
							|  |  |  | 					.then( | 
					
						
							|  |  |  | 						result => | 
					
						
							|  |  |  | 							new Promise((resolve, reject) => { | 
					
						
							|  |  |  | 								if (!result) { | 
					
						
							|  |  |  | 									if (log >= 1) { | 
					
						
							|  |  |  | 										console.warn( | 
					
						
							|  |  |  | 											'Caching failed for pack, because content is flagged as not serializable. Use store: "idle" instead.' | 
					
						
							|  |  |  | 										); | 
					
						
							|  |  |  | 									} | 
					
						
							| 
									
										
										
										
											2018-10-29 21:34:16 +08:00
										 |  |  | 									return resolve(); | 
					
						
							| 
									
										
										
										
											2018-10-23 17:31:20 +08:00
										 |  |  | 								} | 
					
						
							|  |  |  | 								fs.unlink(`${cacheDirectory}.pack`, err => { | 
					
						
							|  |  |  | 									fs.rename( | 
					
						
							|  |  |  | 										`${cacheDirectory}.pack~`, | 
					
						
							|  |  |  | 										`${cacheDirectory}.pack`, | 
					
						
							|  |  |  | 										err => { | 
					
						
							|  |  |  | 											if (err) return reject(err); | 
					
						
							|  |  |  | 											if (log >= 3) { | 
					
						
							|  |  |  | 												console.warn(`Stored pack`); | 
					
						
							|  |  |  | 											} | 
					
						
							|  |  |  | 											resolve(); | 
					
						
							|  |  |  | 										} | 
					
						
							|  |  |  | 									); | 
					
						
							|  |  |  | 								}); | 
					
						
							|  |  |  | 							}) | 
					
						
							|  |  |  | 					) | 
					
						
							|  |  |  | 					.then(() => { | 
					
						
							|  |  |  | 						return serializer.deserializeFromFile(`${cacheDirectory}.pack`); | 
					
						
							|  |  |  | 					}) | 
					
						
							|  |  |  | 					.catch(err => { | 
					
						
							|  |  |  | 						if (log >= 1) { | 
					
						
							|  |  |  | 							console.warn( | 
					
						
							| 
									
										
										
										
											2018-10-23 13:33:45 +08:00
										 |  |  | 								`Caching failed for pack: ${log >= 4 ? err.stack : err}` | 
					
						
							| 
									
										
										
										
											2018-10-23 17:31:20 +08:00
										 |  |  | 							); | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						return new Pack(version); | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 			return packPromise; | 
					
						
							|  |  |  | 		}; | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 		compiler.cache.hooks.shutdown.tapPromise("FileCachePlugin", () => { | 
					
						
							|  |  |  | 			isIdle = false; | 
					
						
							|  |  |  | 			const promises = Array.from(pendingPromiseFactories.values()).map(fn => | 
					
						
							|  |  |  | 				fn() | 
					
						
							|  |  |  | 			); | 
					
						
							|  |  |  | 			pendingPromiseFactories.clear(); | 
					
						
							|  |  |  | 			if (currentIdlePromise !== undefined) promises.push(currentIdlePromise); | 
					
						
							| 
									
										
										
										
											2018-10-23 17:31:20 +08:00
										 |  |  | 			const promise = Promise.all(promises); | 
					
						
							|  |  |  | 			if (store === "pack") { | 
					
						
							|  |  |  | 				return promise.then(serializePack); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return promise; | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 		}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		let currentIdlePromise; | 
					
						
							|  |  |  | 		let isIdle = false; | 
					
						
							|  |  |  | 		const processIdleTasks = () => { | 
					
						
							|  |  |  | 			if (isIdle && pendingPromiseFactories.size > 0) { | 
					
						
							|  |  |  | 				const promises = []; | 
					
						
							|  |  |  | 				const maxTime = Date.now() + 100; | 
					
						
							|  |  |  | 				let maxCount = 100; | 
					
						
							|  |  |  | 				for (const [filename, factory] of pendingPromiseFactories) { | 
					
						
							|  |  |  | 					pendingPromiseFactories.delete(filename); | 
					
						
							|  |  |  | 					promises.push(factory()); | 
					
						
							|  |  |  | 					if (maxCount-- <= 0 || Date.now() > maxTime) break; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				currentIdlePromise = Promise.all(promises).then(() => { | 
					
						
							|  |  |  | 					currentIdlePromise = undefined; | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 				currentIdlePromise.then(processIdleTasks); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}; | 
					
						
							|  |  |  | 		compiler.cache.hooks.beginIdle.tap("FileCachePlugin", () => { | 
					
						
							|  |  |  | 			isIdle = true; | 
					
						
							| 
									
										
										
										
											2018-10-23 17:31:20 +08:00
										 |  |  | 			if (store === "pack") { | 
					
						
							|  |  |  | 				pendingPromiseFactories.delete("pack"); | 
					
						
							|  |  |  | 				pendingPromiseFactories.set("pack", serializePack); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 			Promise.resolve().then(processIdleTasks); | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 		compiler.cache.hooks.endIdle.tap("FileCachePlugin", () => { | 
					
						
							|  |  |  | 			isIdle = false; | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-10-18 04:15:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | module.exports = FileCachePlugin; |