MemoryCachePlugin.js 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const Cache = require("../Cache");
  7. /** @import { Data, Etag } from "../Cache" */
  8. /** @import Compiler from "../Compiler" */
  9. class MemoryCachePlugin {
  10. /**
  11. * Applies the plugin by registering its hooks on the compiler.
  12. * @param {Compiler} compiler the compiler instance
  13. * @returns {void}
  14. */
  15. apply(compiler) {
  16. /** @type {Map<string, { etag: Etag | null, data: Data } | null>} */
  17. const cache = new Map();
  18. compiler.cache.hooks.store.tap(
  19. { name: "MemoryCachePlugin", stage: Cache.STAGE_MEMORY },
  20. (identifier, etag, data) => {
  21. cache.set(identifier, { etag, data });
  22. }
  23. );
  24. compiler.cache.hooks.get.tap(
  25. { name: "MemoryCachePlugin", stage: Cache.STAGE_MEMORY },
  26. (identifier, etag, gotHandlers) => {
  27. const cacheEntry = cache.get(identifier);
  28. // A recorded miss: the whole chain was asked for this identifier already.
  29. if (cacheEntry === null) return null;
  30. // Etags are compared by identity — a lazy one is interned per source
  31. // object, so equal content reached through a second object is a
  32. // different etag. Hashing to tell those apart would cost every hit what
  33. // laziness saves, so a mismatch falls through to the next stage instead:
  34. // the file cache compares etags by value and can still answer. Returning
  35. // `null` here would bail the hook and lose that (`Cache.get` maps it to
  36. // `undefined` regardless, so it buys the caller nothing).
  37. if (cacheEntry !== undefined && cacheEntry.etag === etag) {
  38. return cacheEntry.data;
  39. }
  40. gotHandlers.push((result, callback) => {
  41. if (result !== undefined) {
  42. cache.set(identifier, { etag, data: result });
  43. } else if (cacheEntry === undefined) {
  44. // Record the miss only for an identifier nothing was known about:
  45. // an entry reached with a different etag still answers its own.
  46. cache.set(identifier, null);
  47. }
  48. return callback();
  49. });
  50. }
  51. );
  52. compiler.cache.hooks.shutdown.tap(
  53. { name: "MemoryCachePlugin", stage: Cache.STAGE_MEMORY },
  54. () => {
  55. cache.clear();
  56. }
  57. );
  58. }
  59. }
  60. module.exports = MemoryCachePlugin;