1 | /*
|
---|
2 | MIT License http://www.opensource.org/licenses/mit-license.php
|
---|
3 | Author Tobias Koppers @sokra
|
---|
4 | */
|
---|
5 |
|
---|
6 | "use strict";
|
---|
7 |
|
---|
8 | const { getContext } = require("loader-runner");
|
---|
9 | const asyncLib = require("neo-async");
|
---|
10 | const {
|
---|
11 | AsyncSeriesBailHook,
|
---|
12 | SyncWaterfallHook,
|
---|
13 | SyncBailHook,
|
---|
14 | SyncHook,
|
---|
15 | HookMap
|
---|
16 | } = require("tapable");
|
---|
17 | const ChunkGraph = require("./ChunkGraph");
|
---|
18 | const Module = require("./Module");
|
---|
19 | const ModuleFactory = require("./ModuleFactory");
|
---|
20 | const ModuleGraph = require("./ModuleGraph");
|
---|
21 | const NormalModule = require("./NormalModule");
|
---|
22 | const BasicEffectRulePlugin = require("./rules/BasicEffectRulePlugin");
|
---|
23 | const BasicMatcherRulePlugin = require("./rules/BasicMatcherRulePlugin");
|
---|
24 | const ObjectMatcherRulePlugin = require("./rules/ObjectMatcherRulePlugin");
|
---|
25 | const RuleSetCompiler = require("./rules/RuleSetCompiler");
|
---|
26 | const UseEffectRulePlugin = require("./rules/UseEffectRulePlugin");
|
---|
27 | const LazySet = require("./util/LazySet");
|
---|
28 | const { getScheme } = require("./util/URLAbsoluteSpecifier");
|
---|
29 | const { cachedCleverMerge, cachedSetProperty } = require("./util/cleverMerge");
|
---|
30 | const { join } = require("./util/fs");
|
---|
31 | const { parseResource } = require("./util/identifier");
|
---|
32 |
|
---|
33 | /** @typedef {import("../declarations/WebpackOptions").ModuleOptionsNormalized} ModuleOptions */
|
---|
34 | /** @typedef {import("./Generator")} Generator */
|
---|
35 | /** @typedef {import("./ModuleFactory").ModuleFactoryCreateData} ModuleFactoryCreateData */
|
---|
36 | /** @typedef {import("./ModuleFactory").ModuleFactoryResult} ModuleFactoryResult */
|
---|
37 | /** @typedef {import("./Parser")} Parser */
|
---|
38 | /** @typedef {import("./ResolverFactory")} ResolverFactory */
|
---|
39 | /** @typedef {import("./dependencies/ModuleDependency")} ModuleDependency */
|
---|
40 | /** @typedef {import("./util/fs").InputFileSystem} InputFileSystem */
|
---|
41 |
|
---|
42 | /**
|
---|
43 | * @typedef {Object} ResolveData
|
---|
44 | * @property {ModuleFactoryCreateData["contextInfo"]} contextInfo
|
---|
45 | * @property {ModuleFactoryCreateData["resolveOptions"]} resolveOptions
|
---|
46 | * @property {string} context
|
---|
47 | * @property {string} request
|
---|
48 | * @property {Record<string, any> | undefined} assertions
|
---|
49 | * @property {ModuleDependency[]} dependencies
|
---|
50 | * @property {string} dependencyType
|
---|
51 | * @property {Object} createData
|
---|
52 | * @property {LazySet<string>} fileDependencies
|
---|
53 | * @property {LazySet<string>} missingDependencies
|
---|
54 | * @property {LazySet<string>} contextDependencies
|
---|
55 | * @property {boolean} cacheable allow to use the unsafe cache
|
---|
56 | */
|
---|
57 |
|
---|
58 | /**
|
---|
59 | * @typedef {Object} ResourceData
|
---|
60 | * @property {string} resource
|
---|
61 | * @property {string} path
|
---|
62 | * @property {string} query
|
---|
63 | * @property {string} fragment
|
---|
64 | * @property {string=} context
|
---|
65 | */
|
---|
66 |
|
---|
67 | /** @typedef {ResourceData & { data: Record<string, any> }} ResourceDataWithData */
|
---|
68 |
|
---|
69 | const EMPTY_RESOLVE_OPTIONS = {};
|
---|
70 | const EMPTY_PARSER_OPTIONS = {};
|
---|
71 | const EMPTY_GENERATOR_OPTIONS = {};
|
---|
72 | const EMPTY_ELEMENTS = [];
|
---|
73 |
|
---|
74 | const MATCH_RESOURCE_REGEX = /^([^!]+)!=!/;
|
---|
75 |
|
---|
76 | const loaderToIdent = data => {
|
---|
77 | if (!data.options) {
|
---|
78 | return data.loader;
|
---|
79 | }
|
---|
80 | if (typeof data.options === "string") {
|
---|
81 | return data.loader + "?" + data.options;
|
---|
82 | }
|
---|
83 | if (typeof data.options !== "object") {
|
---|
84 | throw new Error("loader options must be string or object");
|
---|
85 | }
|
---|
86 | if (data.ident) {
|
---|
87 | return data.loader + "??" + data.ident;
|
---|
88 | }
|
---|
89 | return data.loader + "?" + JSON.stringify(data.options);
|
---|
90 | };
|
---|
91 |
|
---|
92 | const stringifyLoadersAndResource = (loaders, resource) => {
|
---|
93 | let str = "";
|
---|
94 | for (const loader of loaders) {
|
---|
95 | str += loaderToIdent(loader) + "!";
|
---|
96 | }
|
---|
97 | return str + resource;
|
---|
98 | };
|
---|
99 |
|
---|
100 | /**
|
---|
101 | * @param {string} resultString resultString
|
---|
102 | * @returns {{loader: string, options: string|undefined}} parsed loader request
|
---|
103 | */
|
---|
104 | const identToLoaderRequest = resultString => {
|
---|
105 | const idx = resultString.indexOf("?");
|
---|
106 | if (idx >= 0) {
|
---|
107 | const loader = resultString.substr(0, idx);
|
---|
108 | const options = resultString.substr(idx + 1);
|
---|
109 | return {
|
---|
110 | loader,
|
---|
111 | options
|
---|
112 | };
|
---|
113 | } else {
|
---|
114 | return {
|
---|
115 | loader: resultString,
|
---|
116 | options: undefined
|
---|
117 | };
|
---|
118 | }
|
---|
119 | };
|
---|
120 |
|
---|
121 | const needCalls = (times, callback) => {
|
---|
122 | return err => {
|
---|
123 | if (--times === 0) {
|
---|
124 | return callback(err);
|
---|
125 | }
|
---|
126 | if (err && times > 0) {
|
---|
127 | times = NaN;
|
---|
128 | return callback(err);
|
---|
129 | }
|
---|
130 | };
|
---|
131 | };
|
---|
132 |
|
---|
133 | const mergeGlobalOptions = (globalOptions, type, localOptions) => {
|
---|
134 | const parts = type.split("/");
|
---|
135 | let result;
|
---|
136 | let current = "";
|
---|
137 | for (const part of parts) {
|
---|
138 | current = current ? `${current}/${part}` : part;
|
---|
139 | const options = globalOptions[current];
|
---|
140 | if (typeof options === "object") {
|
---|
141 | if (result === undefined) {
|
---|
142 | result = options;
|
---|
143 | } else {
|
---|
144 | result = cachedCleverMerge(result, options);
|
---|
145 | }
|
---|
146 | }
|
---|
147 | }
|
---|
148 | if (result === undefined) {
|
---|
149 | return localOptions;
|
---|
150 | } else {
|
---|
151 | return cachedCleverMerge(result, localOptions);
|
---|
152 | }
|
---|
153 | };
|
---|
154 |
|
---|
155 | // TODO webpack 6 remove
|
---|
156 | const deprecationChangedHookMessage = (name, hook) => {
|
---|
157 | const names = hook.taps
|
---|
158 | .map(tapped => {
|
---|
159 | return tapped.name;
|
---|
160 | })
|
---|
161 | .join(", ");
|
---|
162 |
|
---|
163 | return (
|
---|
164 | `NormalModuleFactory.${name} (${names}) is no longer a waterfall hook, but a bailing hook instead. ` +
|
---|
165 | "Do not return the passed object, but modify it instead. " +
|
---|
166 | "Returning false will ignore the request and results in no module created."
|
---|
167 | );
|
---|
168 | };
|
---|
169 |
|
---|
170 | /** @type {WeakMap<ModuleDependency, ModuleFactoryResult & { module: { restoreFromUnsafeCache: Function }}>} */
|
---|
171 | const unsafeCacheDependencies = new WeakMap();
|
---|
172 |
|
---|
173 | /** @type {WeakMap<Module, object>} */
|
---|
174 | const unsafeCacheData = new WeakMap();
|
---|
175 |
|
---|
176 | const ruleSetCompiler = new RuleSetCompiler([
|
---|
177 | new BasicMatcherRulePlugin("test", "resource"),
|
---|
178 | new BasicMatcherRulePlugin("scheme"),
|
---|
179 | new BasicMatcherRulePlugin("mimetype"),
|
---|
180 | new BasicMatcherRulePlugin("dependency"),
|
---|
181 | new BasicMatcherRulePlugin("include", "resource"),
|
---|
182 | new BasicMatcherRulePlugin("exclude", "resource", true),
|
---|
183 | new BasicMatcherRulePlugin("resource"),
|
---|
184 | new BasicMatcherRulePlugin("resourceQuery"),
|
---|
185 | new BasicMatcherRulePlugin("resourceFragment"),
|
---|
186 | new BasicMatcherRulePlugin("realResource"),
|
---|
187 | new BasicMatcherRulePlugin("issuer"),
|
---|
188 | new BasicMatcherRulePlugin("compiler"),
|
---|
189 | new BasicMatcherRulePlugin("issuerLayer"),
|
---|
190 | new ObjectMatcherRulePlugin("assert", "assertions"),
|
---|
191 | new ObjectMatcherRulePlugin("descriptionData"),
|
---|
192 | new BasicEffectRulePlugin("type"),
|
---|
193 | new BasicEffectRulePlugin("sideEffects"),
|
---|
194 | new BasicEffectRulePlugin("parser"),
|
---|
195 | new BasicEffectRulePlugin("resolve"),
|
---|
196 | new BasicEffectRulePlugin("generator"),
|
---|
197 | new BasicEffectRulePlugin("layer"),
|
---|
198 | new UseEffectRulePlugin()
|
---|
199 | ]);
|
---|
200 |
|
---|
201 | class NormalModuleFactory extends ModuleFactory {
|
---|
202 | /**
|
---|
203 | * @param {Object} param params
|
---|
204 | * @param {string=} param.context context
|
---|
205 | * @param {InputFileSystem} param.fs file system
|
---|
206 | * @param {ResolverFactory} param.resolverFactory resolverFactory
|
---|
207 | * @param {ModuleOptions} param.options options
|
---|
208 | * @param {Object=} param.associatedObjectForCache an object to which the cache will be attached
|
---|
209 | * @param {boolean=} param.layers enable layers
|
---|
210 | */
|
---|
211 | constructor({
|
---|
212 | context,
|
---|
213 | fs,
|
---|
214 | resolverFactory,
|
---|
215 | options,
|
---|
216 | associatedObjectForCache,
|
---|
217 | layers = false
|
---|
218 | }) {
|
---|
219 | super();
|
---|
220 | this.hooks = Object.freeze({
|
---|
221 | /** @type {AsyncSeriesBailHook<[ResolveData], TODO>} */
|
---|
222 | resolve: new AsyncSeriesBailHook(["resolveData"]),
|
---|
223 | /** @type {HookMap<AsyncSeriesBailHook<[ResourceDataWithData, ResolveData], true | void>>} */
|
---|
224 | resolveForScheme: new HookMap(
|
---|
225 | () => new AsyncSeriesBailHook(["resourceData", "resolveData"])
|
---|
226 | ),
|
---|
227 | /** @type {HookMap<AsyncSeriesBailHook<[ResourceDataWithData, ResolveData], true | void>>} */
|
---|
228 | resolveInScheme: new HookMap(
|
---|
229 | () => new AsyncSeriesBailHook(["resourceData", "resolveData"])
|
---|
230 | ),
|
---|
231 | /** @type {AsyncSeriesBailHook<[ResolveData], TODO>} */
|
---|
232 | factorize: new AsyncSeriesBailHook(["resolveData"]),
|
---|
233 | /** @type {AsyncSeriesBailHook<[ResolveData], TODO>} */
|
---|
234 | beforeResolve: new AsyncSeriesBailHook(["resolveData"]),
|
---|
235 | /** @type {AsyncSeriesBailHook<[ResolveData], TODO>} */
|
---|
236 | afterResolve: new AsyncSeriesBailHook(["resolveData"]),
|
---|
237 | /** @type {AsyncSeriesBailHook<[ResolveData["createData"], ResolveData], TODO>} */
|
---|
238 | createModule: new AsyncSeriesBailHook(["createData", "resolveData"]),
|
---|
239 | /** @type {SyncWaterfallHook<[Module, ResolveData["createData"], ResolveData], TODO>} */
|
---|
240 | module: new SyncWaterfallHook(["module", "createData", "resolveData"]),
|
---|
241 | createParser: new HookMap(() => new SyncBailHook(["parserOptions"])),
|
---|
242 | parser: new HookMap(() => new SyncHook(["parser", "parserOptions"])),
|
---|
243 | createGenerator: new HookMap(
|
---|
244 | () => new SyncBailHook(["generatorOptions"])
|
---|
245 | ),
|
---|
246 | generator: new HookMap(
|
---|
247 | () => new SyncHook(["generator", "generatorOptions"])
|
---|
248 | )
|
---|
249 | });
|
---|
250 | this.resolverFactory = resolverFactory;
|
---|
251 | this.ruleSet = ruleSetCompiler.compile([
|
---|
252 | {
|
---|
253 | rules: options.defaultRules
|
---|
254 | },
|
---|
255 | {
|
---|
256 | rules: options.rules
|
---|
257 | }
|
---|
258 | ]);
|
---|
259 | this.unsafeCache = !!options.unsafeCache;
|
---|
260 | this.cachePredicate =
|
---|
261 | typeof options.unsafeCache === "function"
|
---|
262 | ? options.unsafeCache
|
---|
263 | : () => true;
|
---|
264 | this.context = context || "";
|
---|
265 | this.fs = fs;
|
---|
266 | this._globalParserOptions = options.parser;
|
---|
267 | this._globalGeneratorOptions = options.generator;
|
---|
268 | /** @type {Map<string, WeakMap<Object, TODO>>} */
|
---|
269 | this.parserCache = new Map();
|
---|
270 | /** @type {Map<string, WeakMap<Object, Generator>>} */
|
---|
271 | this.generatorCache = new Map();
|
---|
272 | /** @type {Set<Module>} */
|
---|
273 | this._restoredUnsafeCacheEntries = new Set();
|
---|
274 |
|
---|
275 | const cacheParseResource = parseResource.bindCache(
|
---|
276 | associatedObjectForCache
|
---|
277 | );
|
---|
278 |
|
---|
279 | this.hooks.factorize.tapAsync(
|
---|
280 | {
|
---|
281 | name: "NormalModuleFactory",
|
---|
282 | stage: 100
|
---|
283 | },
|
---|
284 | (resolveData, callback) => {
|
---|
285 | this.hooks.resolve.callAsync(resolveData, (err, result) => {
|
---|
286 | if (err) return callback(err);
|
---|
287 |
|
---|
288 | // Ignored
|
---|
289 | if (result === false) return callback();
|
---|
290 |
|
---|
291 | // direct module
|
---|
292 | if (result instanceof Module) return callback(null, result);
|
---|
293 |
|
---|
294 | if (typeof result === "object")
|
---|
295 | throw new Error(
|
---|
296 | deprecationChangedHookMessage("resolve", this.hooks.resolve) +
|
---|
297 | " Returning a Module object will result in this module used as result."
|
---|
298 | );
|
---|
299 |
|
---|
300 | this.hooks.afterResolve.callAsync(resolveData, (err, result) => {
|
---|
301 | if (err) return callback(err);
|
---|
302 |
|
---|
303 | if (typeof result === "object")
|
---|
304 | throw new Error(
|
---|
305 | deprecationChangedHookMessage(
|
---|
306 | "afterResolve",
|
---|
307 | this.hooks.afterResolve
|
---|
308 | )
|
---|
309 | );
|
---|
310 |
|
---|
311 | // Ignored
|
---|
312 | if (result === false) return callback();
|
---|
313 |
|
---|
314 | const createData = resolveData.createData;
|
---|
315 |
|
---|
316 | this.hooks.createModule.callAsync(
|
---|
317 | createData,
|
---|
318 | resolveData,
|
---|
319 | (err, createdModule) => {
|
---|
320 | if (!createdModule) {
|
---|
321 | if (!resolveData.request) {
|
---|
322 | return callback(new Error("Empty dependency (no request)"));
|
---|
323 | }
|
---|
324 |
|
---|
325 | createdModule = new NormalModule(createData);
|
---|
326 | }
|
---|
327 |
|
---|
328 | createdModule = this.hooks.module.call(
|
---|
329 | createdModule,
|
---|
330 | createData,
|
---|
331 | resolveData
|
---|
332 | );
|
---|
333 |
|
---|
334 | return callback(null, createdModule);
|
---|
335 | }
|
---|
336 | );
|
---|
337 | });
|
---|
338 | });
|
---|
339 | }
|
---|
340 | );
|
---|
341 | this.hooks.resolve.tapAsync(
|
---|
342 | {
|
---|
343 | name: "NormalModuleFactory",
|
---|
344 | stage: 100
|
---|
345 | },
|
---|
346 | (data, callback) => {
|
---|
347 | const {
|
---|
348 | contextInfo,
|
---|
349 | context,
|
---|
350 | dependencies,
|
---|
351 | dependencyType,
|
---|
352 | request,
|
---|
353 | assertions,
|
---|
354 | resolveOptions,
|
---|
355 | fileDependencies,
|
---|
356 | missingDependencies,
|
---|
357 | contextDependencies
|
---|
358 | } = data;
|
---|
359 | const loaderResolver = this.getResolver("loader");
|
---|
360 |
|
---|
361 | /** @type {ResourceData | undefined} */
|
---|
362 | let matchResourceData = undefined;
|
---|
363 | /** @type {string} */
|
---|
364 | let unresolvedResource;
|
---|
365 | /** @type {{loader: string, options: string|undefined}[]} */
|
---|
366 | let elements;
|
---|
367 | let noPreAutoLoaders = false;
|
---|
368 | let noAutoLoaders = false;
|
---|
369 | let noPrePostAutoLoaders = false;
|
---|
370 |
|
---|
371 | const contextScheme = getScheme(context);
|
---|
372 | /** @type {string | undefined} */
|
---|
373 | let scheme = getScheme(request);
|
---|
374 |
|
---|
375 | if (!scheme) {
|
---|
376 | /** @type {string} */
|
---|
377 | let requestWithoutMatchResource = request;
|
---|
378 | const matchResourceMatch = MATCH_RESOURCE_REGEX.exec(request);
|
---|
379 | if (matchResourceMatch) {
|
---|
380 | let matchResource = matchResourceMatch[1];
|
---|
381 | if (matchResource.charCodeAt(0) === 46) {
|
---|
382 | // 46 === ".", 47 === "/"
|
---|
383 | const secondChar = matchResource.charCodeAt(1);
|
---|
384 | if (
|
---|
385 | secondChar === 47 ||
|
---|
386 | (secondChar === 46 && matchResource.charCodeAt(2) === 47)
|
---|
387 | ) {
|
---|
388 | // if matchResources startsWith ../ or ./
|
---|
389 | matchResource = join(this.fs, context, matchResource);
|
---|
390 | }
|
---|
391 | }
|
---|
392 | matchResourceData = {
|
---|
393 | resource: matchResource,
|
---|
394 | ...cacheParseResource(matchResource)
|
---|
395 | };
|
---|
396 | requestWithoutMatchResource = request.substr(
|
---|
397 | matchResourceMatch[0].length
|
---|
398 | );
|
---|
399 | }
|
---|
400 |
|
---|
401 | scheme = getScheme(requestWithoutMatchResource);
|
---|
402 |
|
---|
403 | if (!scheme && !contextScheme) {
|
---|
404 | const firstChar = requestWithoutMatchResource.charCodeAt(0);
|
---|
405 | const secondChar = requestWithoutMatchResource.charCodeAt(1);
|
---|
406 | noPreAutoLoaders = firstChar === 45 && secondChar === 33; // startsWith "-!"
|
---|
407 | noAutoLoaders = noPreAutoLoaders || firstChar === 33; // startsWith "!"
|
---|
408 | noPrePostAutoLoaders = firstChar === 33 && secondChar === 33; // startsWith "!!";
|
---|
409 | const rawElements = requestWithoutMatchResource
|
---|
410 | .slice(
|
---|
411 | noPreAutoLoaders || noPrePostAutoLoaders
|
---|
412 | ? 2
|
---|
413 | : noAutoLoaders
|
---|
414 | ? 1
|
---|
415 | : 0
|
---|
416 | )
|
---|
417 | .split(/!+/);
|
---|
418 | unresolvedResource = rawElements.pop();
|
---|
419 | elements = rawElements.map(identToLoaderRequest);
|
---|
420 | scheme = getScheme(unresolvedResource);
|
---|
421 | } else {
|
---|
422 | unresolvedResource = requestWithoutMatchResource;
|
---|
423 | elements = EMPTY_ELEMENTS;
|
---|
424 | }
|
---|
425 | } else {
|
---|
426 | unresolvedResource = request;
|
---|
427 | elements = EMPTY_ELEMENTS;
|
---|
428 | }
|
---|
429 |
|
---|
430 | const resolveContext = {
|
---|
431 | fileDependencies,
|
---|
432 | missingDependencies,
|
---|
433 | contextDependencies
|
---|
434 | };
|
---|
435 |
|
---|
436 | /** @type {ResourceDataWithData} */
|
---|
437 | let resourceData;
|
---|
438 |
|
---|
439 | let loaders;
|
---|
440 |
|
---|
441 | const continueCallback = needCalls(2, err => {
|
---|
442 | if (err) return callback(err);
|
---|
443 |
|
---|
444 | // translate option idents
|
---|
445 | try {
|
---|
446 | for (const item of loaders) {
|
---|
447 | if (typeof item.options === "string" && item.options[0] === "?") {
|
---|
448 | const ident = item.options.substr(1);
|
---|
449 | if (ident === "[[missing ident]]") {
|
---|
450 | throw new Error(
|
---|
451 | "No ident is provided by referenced loader. " +
|
---|
452 | "When using a function for Rule.use in config you need to " +
|
---|
453 | "provide an 'ident' property for referenced loader options."
|
---|
454 | );
|
---|
455 | }
|
---|
456 | item.options = this.ruleSet.references.get(ident);
|
---|
457 | if (item.options === undefined) {
|
---|
458 | throw new Error(
|
---|
459 | "Invalid ident is provided by referenced loader"
|
---|
460 | );
|
---|
461 | }
|
---|
462 | item.ident = ident;
|
---|
463 | }
|
---|
464 | }
|
---|
465 | } catch (e) {
|
---|
466 | return callback(e);
|
---|
467 | }
|
---|
468 |
|
---|
469 | if (!resourceData) {
|
---|
470 | // ignored
|
---|
471 | return callback(null, dependencies[0].createIgnoredModule(context));
|
---|
472 | }
|
---|
473 |
|
---|
474 | const userRequest =
|
---|
475 | (matchResourceData !== undefined
|
---|
476 | ? `${matchResourceData.resource}!=!`
|
---|
477 | : "") +
|
---|
478 | stringifyLoadersAndResource(loaders, resourceData.resource);
|
---|
479 |
|
---|
480 | const resourceDataForRules = matchResourceData || resourceData;
|
---|
481 | const result = this.ruleSet.exec({
|
---|
482 | resource: resourceDataForRules.path,
|
---|
483 | realResource: resourceData.path,
|
---|
484 | resourceQuery: resourceDataForRules.query,
|
---|
485 | resourceFragment: resourceDataForRules.fragment,
|
---|
486 | scheme,
|
---|
487 | assertions,
|
---|
488 | mimetype: matchResourceData ? "" : resourceData.data.mimetype || "",
|
---|
489 | dependency: dependencyType,
|
---|
490 | descriptionData: matchResourceData
|
---|
491 | ? undefined
|
---|
492 | : resourceData.data.descriptionFileData,
|
---|
493 | issuer: contextInfo.issuer,
|
---|
494 | compiler: contextInfo.compiler,
|
---|
495 | issuerLayer: contextInfo.issuerLayer || ""
|
---|
496 | });
|
---|
497 | const settings = {};
|
---|
498 | const useLoadersPost = [];
|
---|
499 | const useLoaders = [];
|
---|
500 | const useLoadersPre = [];
|
---|
501 | for (const r of result) {
|
---|
502 | if (r.type === "use") {
|
---|
503 | if (!noAutoLoaders && !noPrePostAutoLoaders) {
|
---|
504 | useLoaders.push(r.value);
|
---|
505 | }
|
---|
506 | } else if (r.type === "use-post") {
|
---|
507 | if (!noPrePostAutoLoaders) {
|
---|
508 | useLoadersPost.push(r.value);
|
---|
509 | }
|
---|
510 | } else if (r.type === "use-pre") {
|
---|
511 | if (!noPreAutoLoaders && !noPrePostAutoLoaders) {
|
---|
512 | useLoadersPre.push(r.value);
|
---|
513 | }
|
---|
514 | } else if (
|
---|
515 | typeof r.value === "object" &&
|
---|
516 | r.value !== null &&
|
---|
517 | typeof settings[r.type] === "object" &&
|
---|
518 | settings[r.type] !== null
|
---|
519 | ) {
|
---|
520 | settings[r.type] = cachedCleverMerge(settings[r.type], r.value);
|
---|
521 | } else {
|
---|
522 | settings[r.type] = r.value;
|
---|
523 | }
|
---|
524 | }
|
---|
525 |
|
---|
526 | let postLoaders, normalLoaders, preLoaders;
|
---|
527 |
|
---|
528 | const continueCallback = needCalls(3, err => {
|
---|
529 | if (err) {
|
---|
530 | return callback(err);
|
---|
531 | }
|
---|
532 | const allLoaders = postLoaders;
|
---|
533 | if (matchResourceData === undefined) {
|
---|
534 | for (const loader of loaders) allLoaders.push(loader);
|
---|
535 | for (const loader of normalLoaders) allLoaders.push(loader);
|
---|
536 | } else {
|
---|
537 | for (const loader of normalLoaders) allLoaders.push(loader);
|
---|
538 | for (const loader of loaders) allLoaders.push(loader);
|
---|
539 | }
|
---|
540 | for (const loader of preLoaders) allLoaders.push(loader);
|
---|
541 | let type = settings.type;
|
---|
542 | if (!type) {
|
---|
543 | const resource =
|
---|
544 | (matchResourceData && matchResourceData.resource) ||
|
---|
545 | resourceData.resource;
|
---|
546 | let match;
|
---|
547 | if (
|
---|
548 | typeof resource === "string" &&
|
---|
549 | (match = /\.webpack\[([^\]]+)\]$/.exec(resource))
|
---|
550 | ) {
|
---|
551 | type = match[1];
|
---|
552 | } else {
|
---|
553 | type = "javascript/auto";
|
---|
554 | }
|
---|
555 | }
|
---|
556 | const resolveOptions = settings.resolve;
|
---|
557 | const layer = settings.layer;
|
---|
558 | if (layer !== undefined && !layers) {
|
---|
559 | return callback(
|
---|
560 | new Error(
|
---|
561 | "'Rule.layer' is only allowed when 'experiments.layers' is enabled"
|
---|
562 | )
|
---|
563 | );
|
---|
564 | }
|
---|
565 | try {
|
---|
566 | Object.assign(data.createData, {
|
---|
567 | layer:
|
---|
568 | layer === undefined ? contextInfo.issuerLayer || null : layer,
|
---|
569 | request: stringifyLoadersAndResource(
|
---|
570 | allLoaders,
|
---|
571 | resourceData.resource
|
---|
572 | ),
|
---|
573 | userRequest,
|
---|
574 | rawRequest: request,
|
---|
575 | loaders: allLoaders,
|
---|
576 | resource: resourceData.resource,
|
---|
577 | context:
|
---|
578 | resourceData.context || getContext(resourceData.resource),
|
---|
579 | matchResource: matchResourceData
|
---|
580 | ? matchResourceData.resource
|
---|
581 | : undefined,
|
---|
582 | resourceResolveData: resourceData.data,
|
---|
583 | settings,
|
---|
584 | type,
|
---|
585 | parser: this.getParser(type, settings.parser),
|
---|
586 | parserOptions: settings.parser,
|
---|
587 | generator: this.getGenerator(type, settings.generator),
|
---|
588 | generatorOptions: settings.generator,
|
---|
589 | resolveOptions
|
---|
590 | });
|
---|
591 | } catch (e) {
|
---|
592 | return callback(e);
|
---|
593 | }
|
---|
594 | callback();
|
---|
595 | });
|
---|
596 | this.resolveRequestArray(
|
---|
597 | contextInfo,
|
---|
598 | this.context,
|
---|
599 | useLoadersPost,
|
---|
600 | loaderResolver,
|
---|
601 | resolveContext,
|
---|
602 | (err, result) => {
|
---|
603 | postLoaders = result;
|
---|
604 | continueCallback(err);
|
---|
605 | }
|
---|
606 | );
|
---|
607 | this.resolveRequestArray(
|
---|
608 | contextInfo,
|
---|
609 | this.context,
|
---|
610 | useLoaders,
|
---|
611 | loaderResolver,
|
---|
612 | resolveContext,
|
---|
613 | (err, result) => {
|
---|
614 | normalLoaders = result;
|
---|
615 | continueCallback(err);
|
---|
616 | }
|
---|
617 | );
|
---|
618 | this.resolveRequestArray(
|
---|
619 | contextInfo,
|
---|
620 | this.context,
|
---|
621 | useLoadersPre,
|
---|
622 | loaderResolver,
|
---|
623 | resolveContext,
|
---|
624 | (err, result) => {
|
---|
625 | preLoaders = result;
|
---|
626 | continueCallback(err);
|
---|
627 | }
|
---|
628 | );
|
---|
629 | });
|
---|
630 |
|
---|
631 | this.resolveRequestArray(
|
---|
632 | contextInfo,
|
---|
633 | contextScheme ? this.context : context,
|
---|
634 | elements,
|
---|
635 | loaderResolver,
|
---|
636 | resolveContext,
|
---|
637 | (err, result) => {
|
---|
638 | if (err) return continueCallback(err);
|
---|
639 | loaders = result;
|
---|
640 | continueCallback();
|
---|
641 | }
|
---|
642 | );
|
---|
643 |
|
---|
644 | const defaultResolve = context => {
|
---|
645 | if (/^($|\?)/.test(unresolvedResource)) {
|
---|
646 | resourceData = {
|
---|
647 | resource: unresolvedResource,
|
---|
648 | data: {},
|
---|
649 | ...cacheParseResource(unresolvedResource)
|
---|
650 | };
|
---|
651 | continueCallback();
|
---|
652 | }
|
---|
653 |
|
---|
654 | // resource without scheme and with path
|
---|
655 | else {
|
---|
656 | const normalResolver = this.getResolver(
|
---|
657 | "normal",
|
---|
658 | dependencyType
|
---|
659 | ? cachedSetProperty(
|
---|
660 | resolveOptions || EMPTY_RESOLVE_OPTIONS,
|
---|
661 | "dependencyType",
|
---|
662 | dependencyType
|
---|
663 | )
|
---|
664 | : resolveOptions
|
---|
665 | );
|
---|
666 | this.resolveResource(
|
---|
667 | contextInfo,
|
---|
668 | context,
|
---|
669 | unresolvedResource,
|
---|
670 | normalResolver,
|
---|
671 | resolveContext,
|
---|
672 | (err, resolvedResource, resolvedResourceResolveData) => {
|
---|
673 | if (err) return continueCallback(err);
|
---|
674 | if (resolvedResource !== false) {
|
---|
675 | resourceData = {
|
---|
676 | resource: resolvedResource,
|
---|
677 | data: resolvedResourceResolveData,
|
---|
678 | ...cacheParseResource(resolvedResource)
|
---|
679 | };
|
---|
680 | }
|
---|
681 | continueCallback();
|
---|
682 | }
|
---|
683 | );
|
---|
684 | }
|
---|
685 | };
|
---|
686 |
|
---|
687 | // resource with scheme
|
---|
688 | if (scheme) {
|
---|
689 | resourceData = {
|
---|
690 | resource: unresolvedResource,
|
---|
691 | data: {},
|
---|
692 | path: undefined,
|
---|
693 | query: undefined,
|
---|
694 | fragment: undefined,
|
---|
695 | context: undefined
|
---|
696 | };
|
---|
697 | this.hooks.resolveForScheme
|
---|
698 | .for(scheme)
|
---|
699 | .callAsync(resourceData, data, err => {
|
---|
700 | if (err) return continueCallback(err);
|
---|
701 | continueCallback();
|
---|
702 | });
|
---|
703 | }
|
---|
704 |
|
---|
705 | // resource within scheme
|
---|
706 | else if (contextScheme) {
|
---|
707 | resourceData = {
|
---|
708 | resource: unresolvedResource,
|
---|
709 | data: {},
|
---|
710 | path: undefined,
|
---|
711 | query: undefined,
|
---|
712 | fragment: undefined,
|
---|
713 | context: undefined
|
---|
714 | };
|
---|
715 | this.hooks.resolveInScheme
|
---|
716 | .for(contextScheme)
|
---|
717 | .callAsync(resourceData, data, (err, handled) => {
|
---|
718 | if (err) return continueCallback(err);
|
---|
719 | if (!handled) return defaultResolve(this.context);
|
---|
720 | continueCallback();
|
---|
721 | });
|
---|
722 | }
|
---|
723 |
|
---|
724 | // resource without scheme and without path
|
---|
725 | else defaultResolve(context);
|
---|
726 | }
|
---|
727 | );
|
---|
728 | }
|
---|
729 |
|
---|
730 | cleanupForCache() {
|
---|
731 | for (const module of this._restoredUnsafeCacheEntries) {
|
---|
732 | ChunkGraph.clearChunkGraphForModule(module);
|
---|
733 | ModuleGraph.clearModuleGraphForModule(module);
|
---|
734 | module.cleanupForCache();
|
---|
735 | }
|
---|
736 | }
|
---|
737 |
|
---|
738 | /**
|
---|
739 | * @param {ModuleFactoryCreateData} data data object
|
---|
740 | * @param {function(Error=, ModuleFactoryResult=): void} callback callback
|
---|
741 | * @returns {void}
|
---|
742 | */
|
---|
743 | create(data, callback) {
|
---|
744 | const dependencies = /** @type {ModuleDependency[]} */ (data.dependencies);
|
---|
745 | if (this.unsafeCache) {
|
---|
746 | const cacheEntry = unsafeCacheDependencies.get(dependencies[0]);
|
---|
747 | if (cacheEntry) {
|
---|
748 | const { module } = cacheEntry;
|
---|
749 | if (!this._restoredUnsafeCacheEntries.has(module)) {
|
---|
750 | const data = unsafeCacheData.get(module);
|
---|
751 | module.restoreFromUnsafeCache(data, this);
|
---|
752 | this._restoredUnsafeCacheEntries.add(module);
|
---|
753 | }
|
---|
754 | return callback(null, cacheEntry);
|
---|
755 | }
|
---|
756 | }
|
---|
757 | const context = data.context || this.context;
|
---|
758 | const resolveOptions = data.resolveOptions || EMPTY_RESOLVE_OPTIONS;
|
---|
759 | const dependency = dependencies[0];
|
---|
760 | const request = dependency.request;
|
---|
761 | const assertions = dependency.assertions;
|
---|
762 | const contextInfo = data.contextInfo;
|
---|
763 | const fileDependencies = new LazySet();
|
---|
764 | const missingDependencies = new LazySet();
|
---|
765 | const contextDependencies = new LazySet();
|
---|
766 | const dependencyType =
|
---|
767 | (dependencies.length > 0 && dependencies[0].category) || "";
|
---|
768 | /** @type {ResolveData} */
|
---|
769 | const resolveData = {
|
---|
770 | contextInfo,
|
---|
771 | resolveOptions,
|
---|
772 | context,
|
---|
773 | request,
|
---|
774 | assertions,
|
---|
775 | dependencies,
|
---|
776 | dependencyType,
|
---|
777 | fileDependencies,
|
---|
778 | missingDependencies,
|
---|
779 | contextDependencies,
|
---|
780 | createData: {},
|
---|
781 | cacheable: true
|
---|
782 | };
|
---|
783 | this.hooks.beforeResolve.callAsync(resolveData, (err, result) => {
|
---|
784 | if (err) {
|
---|
785 | return callback(err, {
|
---|
786 | fileDependencies,
|
---|
787 | missingDependencies,
|
---|
788 | contextDependencies
|
---|
789 | });
|
---|
790 | }
|
---|
791 |
|
---|
792 | // Ignored
|
---|
793 | if (result === false) {
|
---|
794 | return callback(null, {
|
---|
795 | fileDependencies,
|
---|
796 | missingDependencies,
|
---|
797 | contextDependencies
|
---|
798 | });
|
---|
799 | }
|
---|
800 |
|
---|
801 | if (typeof result === "object")
|
---|
802 | throw new Error(
|
---|
803 | deprecationChangedHookMessage(
|
---|
804 | "beforeResolve",
|
---|
805 | this.hooks.beforeResolve
|
---|
806 | )
|
---|
807 | );
|
---|
808 |
|
---|
809 | this.hooks.factorize.callAsync(resolveData, (err, module) => {
|
---|
810 | if (err) {
|
---|
811 | return callback(err, {
|
---|
812 | fileDependencies,
|
---|
813 | missingDependencies,
|
---|
814 | contextDependencies
|
---|
815 | });
|
---|
816 | }
|
---|
817 |
|
---|
818 | const factoryResult = {
|
---|
819 | module,
|
---|
820 | fileDependencies,
|
---|
821 | missingDependencies,
|
---|
822 | contextDependencies
|
---|
823 | };
|
---|
824 |
|
---|
825 | if (
|
---|
826 | this.unsafeCache &&
|
---|
827 | resolveData.cacheable &&
|
---|
828 | module &&
|
---|
829 | module.restoreFromUnsafeCache &&
|
---|
830 | this.cachePredicate(module)
|
---|
831 | ) {
|
---|
832 | for (const d of dependencies) {
|
---|
833 | unsafeCacheDependencies.set(d, factoryResult);
|
---|
834 | }
|
---|
835 | if (!unsafeCacheData.has(module)) {
|
---|
836 | unsafeCacheData.set(module, module.getUnsafeCacheData());
|
---|
837 | }
|
---|
838 | this._restoredUnsafeCacheEntries.add(module);
|
---|
839 | }
|
---|
840 |
|
---|
841 | callback(null, factoryResult);
|
---|
842 | });
|
---|
843 | });
|
---|
844 | }
|
---|
845 |
|
---|
846 | resolveResource(
|
---|
847 | contextInfo,
|
---|
848 | context,
|
---|
849 | unresolvedResource,
|
---|
850 | resolver,
|
---|
851 | resolveContext,
|
---|
852 | callback
|
---|
853 | ) {
|
---|
854 | resolver.resolve(
|
---|
855 | contextInfo,
|
---|
856 | context,
|
---|
857 | unresolvedResource,
|
---|
858 | resolveContext,
|
---|
859 | (err, resolvedResource, resolvedResourceResolveData) => {
|
---|
860 | if (err) {
|
---|
861 | return this._resolveResourceErrorHints(
|
---|
862 | err,
|
---|
863 | contextInfo,
|
---|
864 | context,
|
---|
865 | unresolvedResource,
|
---|
866 | resolver,
|
---|
867 | resolveContext,
|
---|
868 | (err2, hints) => {
|
---|
869 | if (err2) {
|
---|
870 | err.message += `
|
---|
871 | An fatal error happened during resolving additional hints for this error: ${err2.message}`;
|
---|
872 | err.stack += `
|
---|
873 |
|
---|
874 | An fatal error happened during resolving additional hints for this error:
|
---|
875 | ${err2.stack}`;
|
---|
876 | return callback(err);
|
---|
877 | }
|
---|
878 | if (hints && hints.length > 0) {
|
---|
879 | err.message += `
|
---|
880 | ${hints.join("\n\n")}`;
|
---|
881 | }
|
---|
882 | callback(err);
|
---|
883 | }
|
---|
884 | );
|
---|
885 | }
|
---|
886 | callback(err, resolvedResource, resolvedResourceResolveData);
|
---|
887 | }
|
---|
888 | );
|
---|
889 | }
|
---|
890 |
|
---|
891 | _resolveResourceErrorHints(
|
---|
892 | error,
|
---|
893 | contextInfo,
|
---|
894 | context,
|
---|
895 | unresolvedResource,
|
---|
896 | resolver,
|
---|
897 | resolveContext,
|
---|
898 | callback
|
---|
899 | ) {
|
---|
900 | asyncLib.parallel(
|
---|
901 | [
|
---|
902 | callback => {
|
---|
903 | if (!resolver.options.fullySpecified) return callback();
|
---|
904 | resolver
|
---|
905 | .withOptions({
|
---|
906 | fullySpecified: false
|
---|
907 | })
|
---|
908 | .resolve(
|
---|
909 | contextInfo,
|
---|
910 | context,
|
---|
911 | unresolvedResource,
|
---|
912 | resolveContext,
|
---|
913 | (err, resolvedResource) => {
|
---|
914 | if (!err && resolvedResource) {
|
---|
915 | const resource = parseResource(resolvedResource).path.replace(
|
---|
916 | /^.*[\\/]/,
|
---|
917 | ""
|
---|
918 | );
|
---|
919 | return callback(
|
---|
920 | null,
|
---|
921 | `Did you mean '${resource}'?
|
---|
922 | BREAKING CHANGE: The request '${unresolvedResource}' failed to resolve only because it was resolved as fully specified
|
---|
923 | (probably because the origin is strict EcmaScript Module, e. g. a module with javascript mimetype, a '*.mjs' file, or a '*.js' file where the package.json contains '"type": "module"').
|
---|
924 | The extension in the request is mandatory for it to be fully specified.
|
---|
925 | Add the extension to the request.`
|
---|
926 | );
|
---|
927 | }
|
---|
928 | callback();
|
---|
929 | }
|
---|
930 | );
|
---|
931 | },
|
---|
932 | callback => {
|
---|
933 | if (!resolver.options.enforceExtension) return callback();
|
---|
934 | resolver
|
---|
935 | .withOptions({
|
---|
936 | enforceExtension: false,
|
---|
937 | extensions: []
|
---|
938 | })
|
---|
939 | .resolve(
|
---|
940 | contextInfo,
|
---|
941 | context,
|
---|
942 | unresolvedResource,
|
---|
943 | resolveContext,
|
---|
944 | (err, resolvedResource) => {
|
---|
945 | if (!err && resolvedResource) {
|
---|
946 | let hint = "";
|
---|
947 | const match = /(\.[^.]+)(\?|$)/.exec(unresolvedResource);
|
---|
948 | if (match) {
|
---|
949 | const fixedRequest = unresolvedResource.replace(
|
---|
950 | /(\.[^.]+)(\?|$)/,
|
---|
951 | "$2"
|
---|
952 | );
|
---|
953 | if (resolver.options.extensions.has(match[1])) {
|
---|
954 | hint = `Did you mean '${fixedRequest}'?`;
|
---|
955 | } else {
|
---|
956 | hint = `Did you mean '${fixedRequest}'? Also note that '${match[1]}' is not in 'resolve.extensions' yet and need to be added for this to work?`;
|
---|
957 | }
|
---|
958 | } else {
|
---|
959 | hint = `Did you mean to omit the extension or to remove 'resolve.enforceExtension'?`;
|
---|
960 | }
|
---|
961 | return callback(
|
---|
962 | null,
|
---|
963 | `The request '${unresolvedResource}' failed to resolve only because 'resolve.enforceExtension' was specified.
|
---|
964 | ${hint}
|
---|
965 | Including the extension in the request is no longer possible. Did you mean to enforce including the extension in requests with 'resolve.extensions: []' instead?`
|
---|
966 | );
|
---|
967 | }
|
---|
968 | callback();
|
---|
969 | }
|
---|
970 | );
|
---|
971 | },
|
---|
972 | callback => {
|
---|
973 | if (
|
---|
974 | /^\.\.?\//.test(unresolvedResource) ||
|
---|
975 | resolver.options.preferRelative
|
---|
976 | ) {
|
---|
977 | return callback();
|
---|
978 | }
|
---|
979 | resolver.resolve(
|
---|
980 | contextInfo,
|
---|
981 | context,
|
---|
982 | `./${unresolvedResource}`,
|
---|
983 | resolveContext,
|
---|
984 | (err, resolvedResource) => {
|
---|
985 | if (err || !resolvedResource) return callback();
|
---|
986 | const moduleDirectories = resolver.options.modules
|
---|
987 | .map(m => (Array.isArray(m) ? m.join(", ") : m))
|
---|
988 | .join(", ");
|
---|
989 | callback(
|
---|
990 | null,
|
---|
991 | `Did you mean './${unresolvedResource}'?
|
---|
992 | Requests that should resolve in the current directory need to start with './'.
|
---|
993 | Requests that start with a name are treated as module requests and resolve within module directories (${moduleDirectories}).
|
---|
994 | If changing the source code is not an option there is also a resolve options called 'preferRelative' which tries to resolve these kind of requests in the current directory too.`
|
---|
995 | );
|
---|
996 | }
|
---|
997 | );
|
---|
998 | }
|
---|
999 | ],
|
---|
1000 | (err, hints) => {
|
---|
1001 | if (err) return callback(err);
|
---|
1002 | callback(null, hints.filter(Boolean));
|
---|
1003 | }
|
---|
1004 | );
|
---|
1005 | }
|
---|
1006 |
|
---|
1007 | resolveRequestArray(
|
---|
1008 | contextInfo,
|
---|
1009 | context,
|
---|
1010 | array,
|
---|
1011 | resolver,
|
---|
1012 | resolveContext,
|
---|
1013 | callback
|
---|
1014 | ) {
|
---|
1015 | if (array.length === 0) return callback(null, array);
|
---|
1016 | asyncLib.map(
|
---|
1017 | array,
|
---|
1018 | (item, callback) => {
|
---|
1019 | resolver.resolve(
|
---|
1020 | contextInfo,
|
---|
1021 | context,
|
---|
1022 | item.loader,
|
---|
1023 | resolveContext,
|
---|
1024 | (err, result) => {
|
---|
1025 | if (
|
---|
1026 | err &&
|
---|
1027 | /^[^/]*$/.test(item.loader) &&
|
---|
1028 | !/-loader$/.test(item.loader)
|
---|
1029 | ) {
|
---|
1030 | return resolver.resolve(
|
---|
1031 | contextInfo,
|
---|
1032 | context,
|
---|
1033 | item.loader + "-loader",
|
---|
1034 | resolveContext,
|
---|
1035 | err2 => {
|
---|
1036 | if (!err2) {
|
---|
1037 | err.message =
|
---|
1038 | err.message +
|
---|
1039 | "\n" +
|
---|
1040 | "BREAKING CHANGE: It's no longer allowed to omit the '-loader' suffix when using loaders.\n" +
|
---|
1041 | ` You need to specify '${item.loader}-loader' instead of '${item.loader}',\n` +
|
---|
1042 | " see https://webpack.js.org/migrate/3/#automatic-loader-module-name-extension-removed";
|
---|
1043 | }
|
---|
1044 | callback(err);
|
---|
1045 | }
|
---|
1046 | );
|
---|
1047 | }
|
---|
1048 | if (err) return callback(err);
|
---|
1049 |
|
---|
1050 | const parsedResult = identToLoaderRequest(result);
|
---|
1051 | const resolved = {
|
---|
1052 | loader: parsedResult.loader,
|
---|
1053 | options:
|
---|
1054 | item.options === undefined
|
---|
1055 | ? parsedResult.options
|
---|
1056 | : item.options,
|
---|
1057 | ident: item.options === undefined ? undefined : item.ident
|
---|
1058 | };
|
---|
1059 | return callback(null, resolved);
|
---|
1060 | }
|
---|
1061 | );
|
---|
1062 | },
|
---|
1063 | callback
|
---|
1064 | );
|
---|
1065 | }
|
---|
1066 |
|
---|
1067 | getParser(type, parserOptions = EMPTY_PARSER_OPTIONS) {
|
---|
1068 | let cache = this.parserCache.get(type);
|
---|
1069 |
|
---|
1070 | if (cache === undefined) {
|
---|
1071 | cache = new WeakMap();
|
---|
1072 | this.parserCache.set(type, cache);
|
---|
1073 | }
|
---|
1074 |
|
---|
1075 | let parser = cache.get(parserOptions);
|
---|
1076 |
|
---|
1077 | if (parser === undefined) {
|
---|
1078 | parser = this.createParser(type, parserOptions);
|
---|
1079 | cache.set(parserOptions, parser);
|
---|
1080 | }
|
---|
1081 |
|
---|
1082 | return parser;
|
---|
1083 | }
|
---|
1084 |
|
---|
1085 | /**
|
---|
1086 | * @param {string} type type
|
---|
1087 | * @param {{[k: string]: any}} parserOptions parser options
|
---|
1088 | * @returns {Parser} parser
|
---|
1089 | */
|
---|
1090 | createParser(type, parserOptions = {}) {
|
---|
1091 | parserOptions = mergeGlobalOptions(
|
---|
1092 | this._globalParserOptions,
|
---|
1093 | type,
|
---|
1094 | parserOptions
|
---|
1095 | );
|
---|
1096 | const parser = this.hooks.createParser.for(type).call(parserOptions);
|
---|
1097 | if (!parser) {
|
---|
1098 | throw new Error(`No parser registered for ${type}`);
|
---|
1099 | }
|
---|
1100 | this.hooks.parser.for(type).call(parser, parserOptions);
|
---|
1101 | return parser;
|
---|
1102 | }
|
---|
1103 |
|
---|
1104 | getGenerator(type, generatorOptions = EMPTY_GENERATOR_OPTIONS) {
|
---|
1105 | let cache = this.generatorCache.get(type);
|
---|
1106 |
|
---|
1107 | if (cache === undefined) {
|
---|
1108 | cache = new WeakMap();
|
---|
1109 | this.generatorCache.set(type, cache);
|
---|
1110 | }
|
---|
1111 |
|
---|
1112 | let generator = cache.get(generatorOptions);
|
---|
1113 |
|
---|
1114 | if (generator === undefined) {
|
---|
1115 | generator = this.createGenerator(type, generatorOptions);
|
---|
1116 | cache.set(generatorOptions, generator);
|
---|
1117 | }
|
---|
1118 |
|
---|
1119 | return generator;
|
---|
1120 | }
|
---|
1121 |
|
---|
1122 | createGenerator(type, generatorOptions = {}) {
|
---|
1123 | generatorOptions = mergeGlobalOptions(
|
---|
1124 | this._globalGeneratorOptions,
|
---|
1125 | type,
|
---|
1126 | generatorOptions
|
---|
1127 | );
|
---|
1128 | const generator = this.hooks.createGenerator
|
---|
1129 | .for(type)
|
---|
1130 | .call(generatorOptions);
|
---|
1131 | if (!generator) {
|
---|
1132 | throw new Error(`No generator registered for ${type}`);
|
---|
1133 | }
|
---|
1134 | this.hooks.generator.for(type).call(generator, generatorOptions);
|
---|
1135 | return generator;
|
---|
1136 | }
|
---|
1137 |
|
---|
1138 | getResolver(type, resolveOptions) {
|
---|
1139 | return this.resolverFactory.get(type, resolveOptions);
|
---|
1140 | }
|
---|
1141 | }
|
---|
1142 |
|
---|
1143 | module.exports = NormalModuleFactory;
|
---|