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