source: trip-planner-front/node_modules/webpack/lib/NormalModuleFactory.js@ 8d391a1

Last change on this file since 8d391a1 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 31.9 KB
Line 
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6"use strict";
7
8const { getContext } = require("loader-runner");
9const asyncLib = require("neo-async");
10const {
11 AsyncSeriesBailHook,
12 SyncWaterfallHook,
13 SyncBailHook,
14 SyncHook,
15 HookMap
16} = require("tapable");
17const ChunkGraph = require("./ChunkGraph");
18const Module = require("./Module");
19const ModuleFactory = require("./ModuleFactory");
20const ModuleGraph = require("./ModuleGraph");
21const NormalModule = require("./NormalModule");
22const BasicEffectRulePlugin = require("./rules/BasicEffectRulePlugin");
23const BasicMatcherRulePlugin = require("./rules/BasicMatcherRulePlugin");
24const ObjectMatcherRulePlugin = require("./rules/ObjectMatcherRulePlugin");
25const RuleSetCompiler = require("./rules/RuleSetCompiler");
26const UseEffectRulePlugin = require("./rules/UseEffectRulePlugin");
27const LazySet = require("./util/LazySet");
28const { getScheme } = require("./util/URLAbsoluteSpecifier");
29const { cachedCleverMerge, cachedSetProperty } = require("./util/cleverMerge");
30const { join } = require("./util/fs");
31const { 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
69const EMPTY_RESOLVE_OPTIONS = {};
70const EMPTY_PARSER_OPTIONS = {};
71const EMPTY_GENERATOR_OPTIONS = {};
72const EMPTY_ELEMENTS = [];
73
74const MATCH_RESOURCE_REGEX = /^([^!]+)!=!/;
75
76const 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
92const 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 */
104const 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
121const 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
133const 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
156const 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 }}>} */
171const unsafeCacheDependencies = new WeakMap();
172
173/** @type {WeakMap<Module, object>} */
174const unsafeCacheData = new WeakMap();
175
176const 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
201class 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 += `
871An fatal error happened during resolving additional hints for this error: ${err2.message}`;
872 err.stack += `
873
874An 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}'?
922BREAKING 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"').
924The extension in the request is mandatory for it to be fully specified.
925Add 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}
965Including 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}'?
992Requests that should resolve in the current directory need to start with './'.
993Requests that start with a name are treated as module requests and resolve within module directories (${moduleDirectories}).
994If 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
1143module.exports = NormalModuleFactory;
Note: See TracBrowser for help on using the repository browser.