ResolverFactory.js 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const { Tapable, HookMap, SyncHook, SyncWaterfallHook } = require("tapable");
  7. const Factory = require("enhanced-resolve").ResolverFactory;
  8. const { cachedCleverMerge } = require("./util/cleverMerge");
  9. /** @typedef {import("enhanced-resolve").Resolver} Resolver */
  10. const EMTPY_RESOLVE_OPTIONS = {};
  11. module.exports = class ResolverFactory extends Tapable {
  12. constructor() {
  13. super();
  14. this.hooks = {
  15. resolveOptions: new HookMap(
  16. () => new SyncWaterfallHook(["resolveOptions"])
  17. ),
  18. resolver: new HookMap(() => new SyncHook(["resolver", "resolveOptions"]))
  19. };
  20. this._pluginCompat.tap("ResolverFactory", options => {
  21. let match;
  22. match = /^resolve-options (.+)$/.exec(options.name);
  23. if (match) {
  24. this.hooks.resolveOptions
  25. .for(match[1])
  26. .tap(options.fn.name || "unnamed compat plugin", options.fn);
  27. return true;
  28. }
  29. match = /^resolver (.+)$/.exec(options.name);
  30. if (match) {
  31. this.hooks.resolver
  32. .for(match[1])
  33. .tap(options.fn.name || "unnamed compat plugin", options.fn);
  34. return true;
  35. }
  36. });
  37. this.cache2 = new Map();
  38. }
  39. get(type, resolveOptions) {
  40. resolveOptions = resolveOptions || EMTPY_RESOLVE_OPTIONS;
  41. const ident = `${type}|${JSON.stringify(resolveOptions)}`;
  42. const resolver = this.cache2.get(ident);
  43. if (resolver) return resolver;
  44. const newResolver = this._create(type, resolveOptions);
  45. this.cache2.set(ident, newResolver);
  46. return newResolver;
  47. }
  48. _create(type, resolveOptions) {
  49. const originalResolveOptions = Object.assign({}, resolveOptions);
  50. resolveOptions = this.hooks.resolveOptions.for(type).call(resolveOptions);
  51. const resolver = Factory.createResolver(resolveOptions);
  52. if (!resolver) {
  53. throw new Error("No resolver created");
  54. }
  55. /** @type {Map<Object, Resolver>} */
  56. const childCache = new Map();
  57. resolver.withOptions = options => {
  58. const cacheEntry = childCache.get(options);
  59. if (cacheEntry !== undefined) return cacheEntry;
  60. const mergedOptions = cachedCleverMerge(originalResolveOptions, options);
  61. const resolver = this.get(type, mergedOptions);
  62. childCache.set(options, resolver);
  63. return resolver;
  64. };
  65. this.hooks.resolver.for(type).call(resolver, resolveOptions);
  66. return resolver;
  67. }
  68. };