UnsafeCachePlugin.js 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. /** @typedef {import("./Resolver")} Resolver */
  7. /** @typedef {import("./Resolver").ResolveRequest} ResolveRequest */
  8. /** @typedef {import("./Resolver").ResolveStepHook} ResolveStepHook */
  9. /** @typedef {{[k: string]: any}} Cache */
  10. function getCacheId(type, request, withContext) {
  11. return JSON.stringify({
  12. type,
  13. context: withContext ? request.context : "",
  14. path: request.path,
  15. query: request.query,
  16. fragment: request.fragment,
  17. request: request.request
  18. });
  19. }
  20. module.exports = class UnsafeCachePlugin {
  21. /**
  22. * @param {string | ResolveStepHook} source source
  23. * @param {function(ResolveRequest): boolean} filterPredicate filterPredicate
  24. * @param {Cache} cache cache
  25. * @param {boolean} withContext withContext
  26. * @param {string | ResolveStepHook} target target
  27. */
  28. constructor(source, filterPredicate, cache, withContext, target) {
  29. this.source = source;
  30. this.filterPredicate = filterPredicate;
  31. this.withContext = withContext;
  32. this.cache = cache;
  33. this.target = target;
  34. }
  35. /**
  36. * @param {Resolver} resolver the resolver
  37. * @returns {void}
  38. */
  39. apply(resolver) {
  40. const target = resolver.ensureHook(this.target);
  41. resolver
  42. .getHook(this.source)
  43. .tapAsync("UnsafeCachePlugin", (request, resolveContext, callback) => {
  44. if (!this.filterPredicate(request)) return callback();
  45. const isYield = typeof resolveContext.yield === "function";
  46. const cacheId = getCacheId(
  47. isYield ? "yield" : "default",
  48. request,
  49. this.withContext
  50. );
  51. const cacheEntry = this.cache[cacheId];
  52. if (cacheEntry) {
  53. if (isYield) {
  54. const yield_ = /** @type {Function} */ (resolveContext.yield);
  55. if (Array.isArray(cacheEntry)) {
  56. for (const result of cacheEntry) yield_(result);
  57. } else {
  58. yield_(cacheEntry);
  59. }
  60. return callback(null, null);
  61. }
  62. return callback(null, cacheEntry);
  63. }
  64. let yieldFn;
  65. let yield_;
  66. const yieldResult = [];
  67. if (isYield) {
  68. yieldFn = resolveContext.yield;
  69. yield_ = result => {
  70. yieldResult.push(result);
  71. };
  72. }
  73. resolver.doResolve(
  74. target,
  75. request,
  76. null,
  77. yield_ ? { ...resolveContext, yield: yield_ } : resolveContext,
  78. (err, result) => {
  79. if (err) return callback(err);
  80. if (isYield) {
  81. if (result) yieldResult.push(result);
  82. for (const result of yieldResult) yieldFn(result);
  83. this.cache[cacheId] = yieldResult;
  84. return callback(null, null);
  85. }
  86. if (result) return callback(null, (this.cache[cacheId] = result));
  87. callback();
  88. }
  89. );
  90. });
  91. }
  92. };