* Applies the plugin by registering its hooks on the compiler. * @param {Compiler} compiler the compiler instance * @returns {void}
(compiler)
| 35 | * @returns {void} |
| 36 | */ |
| 37 | apply(compiler) { |
| 38 | const maxGenerations = this._maxGenerations; |
| 39 | /** @type {Map<string, { etag: Etag | null, data: Data } | undefined | null>} */ |
| 40 | const cache = new Map(); |
| 41 | /** @type {Map<string, { entry: { etag: Etag | null, data: Data } | null, until: number }>} */ |
| 42 | const oldCache = new Map(); |
| 43 | let generation = 0; |
| 44 | let cachePosition = 0; |
| 45 | const logger = compiler.getInfrastructureLogger(PLUGIN_NAME); |
| 46 | compiler.hooks.afterDone.tap(PLUGIN_NAME, () => { |
| 47 | generation++; |
| 48 | let clearedEntries = 0; |
| 49 | /** @type {undefined | string} */ |
| 50 | let lastClearedIdentifier; |
| 51 | // Avoid coverage problems due indirect changes |
| 52 | /* istanbul ignore next */ |
| 53 | for (const [identifier, entry] of oldCache) { |
| 54 | if (entry.until > generation) break; |
| 55 | |
| 56 | oldCache.delete(identifier); |
| 57 | if (cache.get(identifier) === undefined) { |
| 58 | cache.delete(identifier); |
| 59 | clearedEntries++; |
| 60 | lastClearedIdentifier = identifier; |
| 61 | } |
| 62 | } |
| 63 | if (clearedEntries > 0 || oldCache.size > 0) { |
| 64 | logger.log( |
| 65 | `${cache.size - oldCache.size} active entries, ${ |
| 66 | oldCache.size |
| 67 | } recently unused cached entries${ |
| 68 | clearedEntries > 0 |
| 69 | ? `, ${clearedEntries} old unused cache entries removed e. g. ${lastClearedIdentifier}` |
| 70 | : "" |
| 71 | }` |
| 72 | ); |
| 73 | } |
| 74 | let i = (cache.size / maxGenerations) | 0; |
| 75 | let j = cachePosition >= cache.size ? 0 : cachePosition; |
| 76 | cachePosition = j + i; |
| 77 | for (const [identifier, entry] of cache) { |
| 78 | if (j !== 0) { |
| 79 | j--; |
| 80 | continue; |
| 81 | } |
| 82 | if (entry !== undefined) { |
| 83 | // We don't delete the cache entry, but set it to undefined instead |
| 84 | // This reserves the location in the data table and avoids rehashing |
| 85 | // when constantly adding and removing entries. |
| 86 | // It will be deleted when removed from oldCache. |
| 87 | cache.set(identifier, undefined); |
| 88 | oldCache.delete(identifier); |
| 89 | oldCache.set(identifier, { |
| 90 | entry, |
| 91 | until: generation + maxGenerations |
| 92 | }); |
| 93 | if (i-- === 0) break; |
| 94 | } |