source: frontend/node_modules/webpack/lib/NormalModuleFactory.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 11 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 50.3 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 HookMap,
13 SyncBailHook,
14 SyncHook,
15 SyncWaterfallHook
16} = require("tapable");
17const ChunkGraph = require("./ChunkGraph");
18const Module = require("./Module");
19const ModuleFactory = require("./ModuleFactory");
20const ModuleGraph = require("./ModuleGraph");
21const { JAVASCRIPT_MODULE_TYPE_AUTO } = require("./ModuleTypeConstants");
22const NormalModule = require("./NormalModule");
23const { ImportPhaseUtils } = require("./dependencies/ImportPhase");
24const BasicEffectRulePlugin = require("./rules/BasicEffectRulePlugin");
25const BasicMatcherRulePlugin = require("./rules/BasicMatcherRulePlugin");
26const ObjectMatcherRulePlugin = require("./rules/ObjectMatcherRulePlugin");
27const RuleSetCompiler = require("./rules/RuleSetCompiler");
28const UseEffectRulePlugin = require("./rules/UseEffectRulePlugin");
29const LazySet = require("./util/LazySet");
30const { getScheme } = require("./util/URLAbsoluteSpecifier");
31const { cachedCleverMerge, cachedSetProperty } = require("./util/cleverMerge");
32const { join } = require("./util/fs");
33const {
34 escapeHashInPathRequest,
35 parseResource,
36 parseResourceWithoutFragment
37} = require("./util/identifier");
38
39/** @typedef {import("enhanced-resolve").ResolveContext} ResolveContext */
40/** @typedef {import("enhanced-resolve").ResolveRequest} ResolveRequest */
41/** @typedef {import("../declarations/WebpackOptions").ModuleOptionsNormalized} ModuleOptions */
42/** @typedef {import("../declarations/WebpackOptions").RuleSetRule} RuleSetRule */
43/** @typedef {import("./Compilation").FileSystemDependencies} FileSystemDependencies */
44/** @typedef {import("./Generator")} Generator */
45/** @typedef {import("./ModuleFactory").ModuleFactoryCallback} ModuleFactoryCallback */
46/** @typedef {import("./ModuleFactory").ModuleFactoryCreateData} ModuleFactoryCreateData */
47/** @typedef {import("./ModuleFactory").ModuleFactoryCreateDataContextInfo} ModuleFactoryCreateDataContextInfo */
48/** @typedef {import("./ModuleFactory").ModuleFactoryResult} ModuleFactoryResult */
49/** @typedef {import("./NormalModule").GeneratorOptions} GeneratorOptions */
50/** @typedef {import("./NormalModule").LoaderItem} LoaderItem */
51/** @typedef {import("./NormalModule").NormalModuleCreateData} NormalModuleCreateData */
52/** @typedef {import("./NormalModule").ParserOptions} ParserOptions */
53/** @typedef {import("./Parser")} Parser */
54/** @typedef {import("./ResolverFactory")} ResolverFactory */
55/** @typedef {import("./ResolverFactory").ResolverWithOptions} ResolverWithOptions */
56/** @typedef {import("./dependencies/ModuleDependency")} ModuleDependency */
57/** @typedef {import("./dependencies/ImportPhase").ImportPhaseType} ImportPhaseType */
58/** @typedef {import("./dependencies/ImportPhase").ImportPhaseName} ImportPhaseName */
59/** @typedef {import("./javascript/JavascriptParser").ImportAttributes} ImportAttributes */
60/** @typedef {import("./rules/RuleSetCompiler").RuleSetRules} RuleSetRules */
61/** @typedef {import("./rules/RuleSetCompiler").RuleSet} RuleSet */
62/** @typedef {import("./util/fs").InputFileSystem} InputFileSystem */
63/** @typedef {import("./util/identifier").AssociatedObjectForCache} AssociatedObjectForCache */
64
65/**
66 * Defines the callback type used by this module.
67 * @template T
68 * @typedef {import("./Compiler").Callback<T>} Callback
69 */
70
71/** @typedef {Pick<RuleSetRule, "type" | "sideEffects" | "parser" | "generator" | "resolve" | "layer" | "extractSourceMap">} ModuleSettings */
72/** @typedef {NormalModuleCreateData & { settings: ModuleSettings }} CreateData */
73
74/**
75 * Defines the resolve data type used by this module.
76 * @typedef {object} ResolveData
77 * @property {ModuleFactoryCreateData["contextInfo"]} contextInfo
78 * @property {ModuleFactoryCreateData["resolveOptions"]} resolveOptions
79 * @property {string} context
80 * @property {string} request
81 * @property {ImportPhaseName=} phase
82 * @property {ImportAttributes=} attributes
83 * @property {ModuleDependency[]} dependencies
84 * @property {string} dependencyType
85 * @property {Partial<CreateData>} createData
86 * @property {FileSystemDependencies} fileDependencies
87 * @property {FileSystemDependencies} missingDependencies
88 * @property {FileSystemDependencies} contextDependencies
89 * @property {Module=} ignoredModule
90 * @property {boolean} cacheable allow to use the unsafe cache
91 */
92
93/**
94 * Defines the resource data type used by this module.
95 * @typedef {object} ResourceData
96 * @property {string} resource
97 * @property {string=} path
98 * @property {string=} query
99 * @property {string=} fragment
100 * @property {string=} context
101 */
102
103/**
104 * Defines the resource scheme data type used by this module.
105 * @typedef {object} ResourceSchemeData
106 * @property {string=} mimetype mime type of the resource
107 * @property {string=} parameters additional parameters for the resource
108 * @property {"base64" | false=} encoding encoding of the resource
109 * @property {string=} encodedContent encoded content of the resource
110 */
111
112/** @typedef {ResourceData & { data: ResourceSchemeData & Partial<ResolveRequest> }} ResourceDataWithData */
113
114/**
115 * Defines the parsed loader request type used by this module.
116 * @typedef {object} ParsedLoaderRequest
117 * @property {string} loader loader
118 * @property {string | undefined} options options
119 */
120
121/** @typedef {import("./ModuleTypeConstants").JAVASCRIPT_MODULE_TYPE_AUTO} JAVASCRIPT_MODULE_TYPE_AUTO */
122/** @typedef {import("./ModuleTypeConstants").JAVASCRIPT_MODULE_TYPE_DYNAMIC} JAVASCRIPT_MODULE_TYPE_DYNAMIC */
123/** @typedef {import("./ModuleTypeConstants").JAVASCRIPT_MODULE_TYPE_ESM} JAVASCRIPT_MODULE_TYPE_ESM */
124/** @typedef {import("./ModuleTypeConstants").JSON_MODULE_TYPE} JSON_MODULE_TYPE */
125/** @typedef {import("./ModuleTypeConstants").ASSET_MODULE_TYPE} ASSET_MODULE_TYPE */
126/** @typedef {import("./ModuleTypeConstants").ASSET_MODULE_TYPE_INLINE} ASSET_MODULE_TYPE_INLINE */
127/** @typedef {import("./ModuleTypeConstants").ASSET_MODULE_TYPE_RESOURCE} ASSET_MODULE_TYPE_RESOURCE */
128/** @typedef {import("./ModuleTypeConstants").ASSET_MODULE_TYPE_SOURCE} ASSET_MODULE_TYPE_SOURCE */
129/** @typedef {import("./ModuleTypeConstants").ASSET_MODULE_TYPE_BYTES} ASSET_MODULE_TYPE_BYTES */
130/** @typedef {import("./ModuleTypeConstants").WEBASSEMBLY_MODULE_TYPE_ASYNC} WEBASSEMBLY_MODULE_TYPE_ASYNC */
131/** @typedef {import("./ModuleTypeConstants").WEBASSEMBLY_MODULE_TYPE_SYNC} WEBASSEMBLY_MODULE_TYPE_SYNC */
132/** @typedef {import("./ModuleTypeConstants").CSS_MODULE_TYPE} CSS_MODULE_TYPE */
133/** @typedef {import("./ModuleTypeConstants").CSS_MODULE_TYPE_GLOBAL} CSS_MODULE_TYPE_GLOBAL */
134/** @typedef {import("./ModuleTypeConstants").CSS_MODULE_TYPE_MODULE} CSS_MODULE_TYPE_MODULE */
135/** @typedef {import("./ModuleTypeConstants").CSS_MODULE_TYPE_AUTO} CSS_MODULE_TYPE_AUTO */
136/** @typedef {import("./ModuleTypeConstants").HTML_MODULE_TYPE} HTML_MODULE_TYPE */
137
138/** @typedef {JAVASCRIPT_MODULE_TYPE_AUTO | JAVASCRIPT_MODULE_TYPE_DYNAMIC | JAVASCRIPT_MODULE_TYPE_ESM | JSON_MODULE_TYPE | ASSET_MODULE_TYPE | ASSET_MODULE_TYPE_INLINE | ASSET_MODULE_TYPE_RESOURCE | ASSET_MODULE_TYPE_SOURCE | WEBASSEMBLY_MODULE_TYPE_ASYNC | WEBASSEMBLY_MODULE_TYPE_SYNC | CSS_MODULE_TYPE | CSS_MODULE_TYPE_GLOBAL | CSS_MODULE_TYPE_MODULE | CSS_MODULE_TYPE_AUTO | HTML_MODULE_TYPE} KnownNormalModuleTypes */
139/** @typedef {KnownNormalModuleTypes | string} NormalModuleTypes */
140
141const EMPTY_RESOLVE_OPTIONS = {};
142/** @type {ParserOptions} */
143const EMPTY_PARSER_OPTIONS = {};
144/** @type {GeneratorOptions} */
145const EMPTY_GENERATOR_OPTIONS = {};
146/** @type {ParsedLoaderRequest[]} */
147const EMPTY_ELEMENTS = [];
148
149const MATCH_RESOURCE_REGEX = /^([^!]+)!=!/;
150const LEADING_DOT_EXTENSION_REGEX = /^[^.]/;
151
152/**
153 * Returns ident.
154 * @param {LoaderItem} data data
155 * @returns {string} ident
156 */
157const loaderToIdent = (data) => {
158 if (!data.options) {
159 return data.loader;
160 }
161 if (typeof data.options === "string") {
162 return `${data.loader}?${data.options}`;
163 }
164 if (typeof data.options !== "object") {
165 throw new Error("loader options must be string or object");
166 }
167 if (data.ident) {
168 return `${data.loader}??${data.ident}`;
169 }
170 return `${data.loader}?${JSON.stringify(data.options)}`;
171};
172
173/**
174 * Stringify loaders and resource.
175 * @param {LoaderItem[]} loaders loaders
176 * @param {string} resource resource
177 * @returns {string} stringified loaders and resource
178 */
179const stringifyLoadersAndResource = (loaders, resource) => {
180 let str = "";
181 for (const loader of loaders) {
182 str += `${loaderToIdent(loader)}!`;
183 }
184 return str + resource;
185};
186
187/**
188 * Checks whether it needs calls.
189 * @param {number} times times
190 * @param {(err?: null | Error) => void} callback callback
191 * @returns {(err?: null | Error) => void} callback
192 */
193const needCalls = (times, callback) => (err) => {
194 if (--times === 0) {
195 return callback(err);
196 }
197 if (err && times > 0) {
198 times = Number.NaN;
199 return callback(err);
200 }
201};
202
203/**
204 * Merges global options.
205 * @template T
206 * @template O
207 * @param {T} globalOptions global options
208 * @param {string} type type
209 * @param {O} localOptions local options
210 * @returns {T & O | T | O} result
211 */
212const mergeGlobalOptions = (globalOptions, type, localOptions) => {
213 const parts = type.split("/");
214 /** @type {undefined | T} */
215 let result;
216 let current = "";
217 for (const part of parts) {
218 current = current ? `${current}/${part}` : part;
219 const options =
220 /** @type {T} */
221 (globalOptions[/** @type {keyof T} */ (current)]);
222 if (typeof options === "object") {
223 result =
224 result === undefined ? options : cachedCleverMerge(result, options);
225 }
226 }
227 if (result === undefined) {
228 return localOptions;
229 }
230 return cachedCleverMerge(result, localOptions);
231};
232
233// TODO webpack 6 remove
234/**
235 * Deprecation changed hook message.
236 * @template {import("tapable").Hook<EXPECTED_ANY, EXPECTED_ANY>} T
237 * @param {string} name name
238 * @param {T} hook hook
239 * @returns {string} result
240 */
241const deprecationChangedHookMessage = (name, hook) => {
242 const names = hook.taps.map((tapped) => tapped.name).join(", ");
243
244 return (
245 `NormalModuleFactory.${name} (${names}) is no longer a waterfall hook, but a bailing hook instead. ` +
246 "Do not return the passed object, but modify it instead. " +
247 "Returning false will ignore the request and results in no module created."
248 );
249};
250
251const ruleSetCompiler = new RuleSetCompiler([
252 new BasicMatcherRulePlugin("test", "resource"),
253 new BasicMatcherRulePlugin("scheme"),
254 new BasicMatcherRulePlugin("mimetype"),
255 new BasicMatcherRulePlugin("dependency"),
256 new BasicMatcherRulePlugin("include", "resource"),
257 new BasicMatcherRulePlugin("exclude", "resource", true),
258 new BasicMatcherRulePlugin("resource"),
259 new BasicMatcherRulePlugin("resourceQuery"),
260 new BasicMatcherRulePlugin("resourceFragment"),
261 new BasicMatcherRulePlugin("realResource"),
262 new BasicMatcherRulePlugin("issuer"),
263 new BasicMatcherRulePlugin("compiler"),
264 new BasicMatcherRulePlugin("issuerLayer"),
265 new BasicMatcherRulePlugin("phase"),
266 new ObjectMatcherRulePlugin("assert", "attributes", (value) => {
267 if (value) {
268 return (
269 /** @type {ImportAttributes} */ (value)._isLegacyAssert !== undefined
270 );
271 }
272
273 return false;
274 }),
275 new ObjectMatcherRulePlugin("with", "attributes", (value) => {
276 if (value) {
277 return !(/** @type {ImportAttributes} */ (value)._isLegacyAssert);
278 }
279 return false;
280 }),
281 new ObjectMatcherRulePlugin("descriptionData"),
282 new BasicEffectRulePlugin("type"),
283 new BasicEffectRulePlugin("sideEffects"),
284 new BasicEffectRulePlugin("parser"),
285 new BasicEffectRulePlugin("resolve"),
286 new BasicEffectRulePlugin("generator"),
287 new BasicEffectRulePlugin("layer"),
288 new BasicEffectRulePlugin("extractSourceMap"),
289 new UseEffectRulePlugin()
290]);
291
292/** @typedef {import("./javascript/JavascriptParser")} JavascriptParser */
293/** @typedef {import("../declarations/WebpackOptions").JavascriptParserOptions} JavascriptParserOptions */
294/** @typedef {import("./javascript/JavascriptGenerator")} JavascriptGenerator */
295/** @typedef {import("../declarations/WebpackOptions").EmptyGeneratorOptions} EmptyGeneratorOptions */
296
297/** @typedef {import("./json/JsonParser")} JsonParser */
298/** @typedef {import("../declarations/WebpackOptions").JsonParserOptions} JsonParserOptions */
299/** @typedef {import("./json/JsonGenerator")} JsonGenerator */
300/** @typedef {import("../declarations/WebpackOptions").JsonGeneratorOptions} JsonGeneratorOptions */
301
302/** @typedef {import("./asset/AssetParser")} AssetParser */
303/** @typedef {import("./asset/AssetSourceParser")} AssetSourceParser */
304/** @typedef {import("./asset/AssetBytesParser")} AssetBytesParser */
305/** @typedef {import("../declarations/WebpackOptions").AssetParserOptions} AssetParserOptions */
306/** @typedef {import("../declarations/WebpackOptions").EmptyParserOptions} EmptyParserOptions */
307/** @typedef {import("./asset/AssetGenerator")} AssetGenerator */
308/** @typedef {import("../declarations/WebpackOptions").AssetGeneratorOptions} AssetGeneratorOptions */
309/** @typedef {import("../declarations/WebpackOptions").AssetInlineGeneratorOptions} AssetInlineGeneratorOptions */
310/** @typedef {import("../declarations/WebpackOptions").AssetResourceGeneratorOptions} AssetResourceGeneratorOptions */
311/** @typedef {import("./asset/AssetSourceGenerator")} AssetSourceGenerator */
312/** @typedef {import("./asset/AssetBytesGenerator")} AssetBytesGenerator */
313
314/** @typedef {import("./wasm-async/AsyncWebAssemblyParser")} AsyncWebAssemblyParser */
315/** @typedef {import("./wasm-sync/WebAssemblyParser")} WebAssemblyParser */
316
317/** @typedef {import("./css/CssParser")} CssParser */
318/** @typedef {import("../declarations/WebpackOptions").CssParserOptions} CssParserOptions */
319/** @typedef {import("../declarations/WebpackOptions").CssModuleParserOptions} CssModuleParserOptions */
320/** @typedef {import("./css/CssGenerator")} CssGenerator */
321/** @typedef {import("../declarations/WebpackOptions").CssGeneratorOptions} CssGeneratorOptions */
322/** @typedef {import("../declarations/WebpackOptions").CssModuleGeneratorOptions} CssModuleGeneratorOptions */
323
324/** @typedef {import("./html/HtmlParser")} HtmlParser */
325/** @typedef {import("../declarations/WebpackOptions").EmptyParserOptions} HtmlParserOptions */
326/** @typedef {import("./html/HtmlGenerator")} HtmlGenerator */
327/** @typedef {import("../declarations/WebpackOptions").HtmlGeneratorOptions} HtmlGeneratorOptions */
328
329/* eslint-disable jsdoc/type-formatting */
330/**
331 * Defines the shared type used by this module.
332 * @typedef {[
333 * [JAVASCRIPT_MODULE_TYPE_AUTO, JavascriptParser, JavascriptParserOptions, JavascriptGenerator, EmptyGeneratorOptions],
334 * [JAVASCRIPT_MODULE_TYPE_DYNAMIC, JavascriptParser, JavascriptParserOptions, JavascriptGenerator, EmptyGeneratorOptions],
335 * [JAVASCRIPT_MODULE_TYPE_ESM, JavascriptParser, JavascriptParserOptions, JavascriptGenerator, EmptyGeneratorOptions],
336 * [JSON_MODULE_TYPE, JsonParser, JsonParserOptions, JsonGenerator, JsonGeneratorOptions],
337 * [ASSET_MODULE_TYPE, AssetParser, AssetParserOptions, AssetGenerator, AssetGeneratorOptions],
338 * [ASSET_MODULE_TYPE_INLINE, AssetParser, EmptyParserOptions, AssetGenerator, AssetGeneratorOptions],
339 * [ASSET_MODULE_TYPE_RESOURCE, AssetParser, EmptyParserOptions, AssetGenerator, AssetGeneratorOptions],
340 * [ASSET_MODULE_TYPE_SOURCE, AssetSourceParser, EmptyParserOptions, AssetSourceGenerator, EmptyGeneratorOptions],
341 * [ASSET_MODULE_TYPE_BYTES, AssetBytesParser, EmptyParserOptions, AssetBytesGenerator, EmptyGeneratorOptions],
342 * [WEBASSEMBLY_MODULE_TYPE_ASYNC, AsyncWebAssemblyParser, EmptyParserOptions, Generator, EmptyGeneratorOptions],
343 * [WEBASSEMBLY_MODULE_TYPE_SYNC, WebAssemblyParser, EmptyParserOptions, Generator, EmptyGeneratorOptions],
344 * [CSS_MODULE_TYPE, CssParser, CssParserOptions, CssGenerator, CssGeneratorOptions],
345 * [CSS_MODULE_TYPE_AUTO, CssParser, CssModuleParserOptions, CssGenerator, CssModuleGeneratorOptions],
346 * [CSS_MODULE_TYPE_MODULE, CssParser, CssModuleParserOptions, CssGenerator, CssModuleGeneratorOptions],
347 * [CSS_MODULE_TYPE_GLOBAL, CssParser, CssModuleParserOptions, CssGenerator, CssModuleGeneratorOptions],
348 * [HTML_MODULE_TYPE, HtmlParser, HtmlParserOptions, HtmlGenerator, HtmlGeneratorOptions],
349 * [string, Parser, ParserOptions, Generator, GeneratorOptions],
350 * ]} ParsersAndGeneratorsByTypes
351 */
352/* eslint-enable jsdoc/type-formatting */
353
354/**
355 * Defines the extract tuple elements type used by this module.
356 * @template {unknown[]} T
357 * @template {number[]} I
358 * @typedef {{ [K in keyof I]: K extends keyof I ? I[K] extends keyof T ? T[I[K]] : never : never }} ExtractTupleElements
359 */
360
361/**
362 * Represents the normal module factory runtime component.
363 * @template {unknown[]} T
364 * @template {number[]} A
365 * @template [R=void]
366 * @typedef {T extends [infer Head extends [string, ...unknown[]], ...infer Tail extends [string, ...unknown[]][]] ? Record<Head[0], SyncBailHook<ExtractTupleElements<Head, A>, R extends number ? Head[R] : R>> & RecordFactoryFromTuple<Tail, A, R> : unknown } RecordFactoryFromTuple
367 */
368
369/**
370 * Maps each tuple in `T` to a record from its `[0]` key to its `[I]` value.
371 * @template {unknown[]} T
372 * @template {number} I
373 * @typedef {T extends [infer Head extends [string, ...unknown[]], ...infer Tail extends [string, ...unknown[]][]] ? Record<Head[0], I extends keyof Head ? Head[I] : never> & TupleToTypeMap<Tail, I> : unknown } TupleToTypeMap
374 */
375
376/** @typedef {TupleToTypeMap<ParsersAndGeneratorsByTypes, 1>} ParserByType */
377/** @typedef {TupleToTypeMap<ParsersAndGeneratorsByTypes, 2>} ParserOptionsByType */
378/** @typedef {TupleToTypeMap<ParsersAndGeneratorsByTypes, 3>} GeneratorByType */
379/** @typedef {TupleToTypeMap<ParsersAndGeneratorsByTypes, 4>} GeneratorOptionsByType */
380
381class NormalModuleFactory extends ModuleFactory {
382 /**
383 * Creates an instance of NormalModuleFactory.
384 * @param {object} param params
385 * @param {string=} param.context context
386 * @param {InputFileSystem} param.fs file system
387 * @param {ResolverFactory} param.resolverFactory resolverFactory
388 * @param {ModuleOptions} param.options options
389 * @param {AssociatedObjectForCache} param.associatedObjectForCache an object to which the cache will be attached
390 */
391 constructor({
392 context,
393 fs,
394 resolverFactory,
395 options,
396 associatedObjectForCache
397 }) {
398 super();
399 this.hooks = Object.freeze({
400 /** @type {AsyncSeriesBailHook<[ResolveData], Module | false | void>} */
401 resolve: new AsyncSeriesBailHook(["resolveData"]),
402 /** @type {HookMap<AsyncSeriesBailHook<[ResourceDataWithData, ResolveData], true | void>>} */
403 resolveForScheme: new HookMap(
404 () => new AsyncSeriesBailHook(["resourceData", "resolveData"])
405 ),
406 /** @type {HookMap<AsyncSeriesBailHook<[ResourceDataWithData, ResolveData], true | void>>} */
407 resolveInScheme: new HookMap(
408 () => new AsyncSeriesBailHook(["resourceData", "resolveData"])
409 ),
410 /** @type {AsyncSeriesBailHook<[ResolveData], Module | undefined>} */
411 factorize: new AsyncSeriesBailHook(["resolveData"]),
412 /** @type {AsyncSeriesBailHook<[ResolveData], false | void>} */
413 beforeResolve: new AsyncSeriesBailHook(["resolveData"]),
414 /** @type {AsyncSeriesBailHook<[ResolveData], false | void>} */
415 afterResolve: new AsyncSeriesBailHook(["resolveData"]),
416 /** @type {AsyncSeriesBailHook<[CreateData, ResolveData], Module | void>} */
417 createModule: new AsyncSeriesBailHook(["createData", "resolveData"]),
418 /** @type {SyncWaterfallHook<[Module, CreateData, ResolveData]>} */
419 module: new SyncWaterfallHook(["module", "createData", "resolveData"]),
420 /** @type {import("tapable").TypedHookMap<RecordFactoryFromTuple<ParsersAndGeneratorsByTypes, [2], 1>>} */
421 createParser: new HookMap(() => new SyncBailHook(["parserOptions"])),
422 /** @type {import("tapable").TypedHookMap<RecordFactoryFromTuple<ParsersAndGeneratorsByTypes, [1, 2]>>} */
423 parser: new HookMap(() => new SyncHook(["parser", "parserOptions"])),
424 /** @type {import("tapable").TypedHookMap<RecordFactoryFromTuple<ParsersAndGeneratorsByTypes, [4], 3>>} */
425 createGenerator: new HookMap(
426 () => new SyncBailHook(["generatorOptions"])
427 ),
428 /** @type {import("tapable").TypedHookMap<RecordFactoryFromTuple<ParsersAndGeneratorsByTypes, [3, 4]>>} */
429 generator: new HookMap(
430 () => new SyncHook(["generator", "generatorOptions"])
431 ),
432 /** @type {HookMap<SyncBailHook<[CreateData, ResolveData], Module | void>>} */
433 createModuleClass: new HookMap(
434 () => new SyncBailHook(["createData", "resolveData"])
435 )
436 });
437 /** @type {ResolverFactory} */
438 this.resolverFactory = resolverFactory;
439 /** @type {RuleSet} */
440 this.ruleSet = ruleSetCompiler.compile([
441 {
442 rules: /** @type {RuleSetRules} */ (options.defaultRules)
443 },
444 {
445 rules: /** @type {RuleSetRules} */ (options.rules)
446 }
447 ]);
448 /** @type {string} */
449 this.context = context || "";
450 /** @type {InputFileSystem} */
451 this.fs = fs;
452 this._globalParserOptions = options.parser;
453 this._globalGeneratorOptions = options.generator;
454 /** @type {Map<string, WeakMap<ParserOptions, Parser>>} */
455 this.parserCache = new Map();
456 /** @type {Map<string, WeakMap<GeneratorOptions, Generator>>} */
457 this.generatorCache = new Map();
458 /** @type {Set<Module>} */
459 this._restoredUnsafeCacheEntries = new Set();
460
461 /** @type {(resource: string) => import("./util/identifier").ParsedResource} */
462 const cacheParseResource = parseResource.bindCache(
463 associatedObjectForCache
464 );
465 const cachedParseResourceWithoutFragment =
466 parseResourceWithoutFragment.bindCache(associatedObjectForCache);
467 this._parseResourceWithoutFragment = cachedParseResourceWithoutFragment;
468
469 this.hooks.factorize.tapAsync(
470 {
471 name: "NormalModuleFactory",
472 stage: 100
473 },
474 (resolveData, callback) => {
475 this.hooks.resolve.callAsync(resolveData, (err, result) => {
476 if (err) return callback(err);
477
478 // Ignored
479 if (result === false) return callback();
480
481 // direct module
482 if (result instanceof Module) return callback(null, result);
483
484 if (typeof result === "object") {
485 throw new Error(
486 `${deprecationChangedHookMessage(
487 "resolve",
488 this.hooks.resolve
489 )} Returning a Module object will result in this module used as result.`
490 );
491 }
492
493 this.hooks.afterResolve.callAsync(resolveData, (err, result) => {
494 if (err) return callback(err);
495
496 if (typeof result === "object") {
497 throw new Error(
498 deprecationChangedHookMessage(
499 "afterResolve",
500 this.hooks.afterResolve
501 )
502 );
503 }
504
505 // Ignored
506 if (result === false) return callback();
507
508 const createData =
509 /** @type {CreateData} */
510 (resolveData.createData);
511
512 this.hooks.createModule.callAsync(
513 createData,
514 resolveData,
515 (err, createdModule) => {
516 if (!createdModule) {
517 if (!resolveData.request) {
518 return callback(new Error("Empty dependency (no request)"));
519 }
520
521 // TODO webpack 6 make it required and move javascript/wasm/asset properties to own module
522 createdModule = this.hooks.createModuleClass
523 .for(createData.settings.type)
524 .call(createData, resolveData);
525
526 if (!createdModule) {
527 createdModule = /** @type {Module} */ (
528 new NormalModule(createData)
529 );
530 }
531 }
532
533 createdModule = this.hooks.module.call(
534 createdModule,
535 createData,
536 resolveData
537 );
538
539 return callback(null, createdModule);
540 }
541 );
542 });
543 });
544 }
545 );
546 this.hooks.resolve.tapAsync(
547 {
548 name: "NormalModuleFactory",
549 stage: 100
550 },
551 (data, callback) => {
552 const {
553 contextInfo,
554 context,
555 dependencies,
556 dependencyType,
557 request,
558 phase,
559 attributes,
560 resolveOptions,
561 fileDependencies,
562 missingDependencies,
563 contextDependencies
564 } = data;
565 const loaderResolver = this.getResolver("loader");
566
567 /** @type {ResourceData | undefined} */
568 let matchResourceData;
569 /** @type {string} */
570 let unresolvedResource;
571 /** @type {ParsedLoaderRequest[]} */
572 let elements;
573 let noPreAutoLoaders = false;
574 let noAutoLoaders = false;
575 let noPrePostAutoLoaders = false;
576
577 const contextScheme = getScheme(context);
578 /** @type {string | undefined} */
579 let scheme = getScheme(request);
580
581 if (!scheme) {
582 /** @type {string} */
583 let requestWithoutMatchResource = request;
584 const matchResourceMatch = MATCH_RESOURCE_REGEX.exec(request);
585 if (matchResourceMatch) {
586 let matchResource = matchResourceMatch[1];
587 // Check if matchResource starts with ./ or ../
588 if (matchResource.charCodeAt(0) === 46) {
589 // 46 is "."
590 const secondChar = matchResource.charCodeAt(1);
591 if (
592 secondChar === 47 || // 47 is "/"
593 (secondChar === 46 && matchResource.charCodeAt(2) === 47) // "../"
594 ) {
595 // Resolve relative path against context
596 matchResource = join(this.fs, context, matchResource);
597 }
598 }
599
600 matchResourceData = {
601 ...cacheParseResource(matchResource),
602 resource: matchResource
603 };
604 requestWithoutMatchResource = request.slice(
605 matchResourceMatch[0].length
606 );
607 }
608
609 scheme = getScheme(requestWithoutMatchResource);
610
611 if (!scheme && !contextScheme) {
612 const firstChar = requestWithoutMatchResource.charCodeAt(0);
613 const secondChar = requestWithoutMatchResource.charCodeAt(1);
614 noPreAutoLoaders = firstChar === 45 && secondChar === 33; // startsWith "-!"
615 noAutoLoaders = noPreAutoLoaders || firstChar === 33; // startsWith "!"
616 noPrePostAutoLoaders = firstChar === 33 && secondChar === 33; // startsWith "!!";
617 const rawElements = requestWithoutMatchResource
618 .slice(
619 noPreAutoLoaders || noPrePostAutoLoaders
620 ? 2
621 : noAutoLoaders
622 ? 1
623 : 0
624 )
625 .split(/!+/);
626 unresolvedResource = /** @type {string} */ (rawElements.pop());
627 elements = rawElements.map((el) => {
628 const { path, query } = cachedParseResourceWithoutFragment(el);
629 return {
630 loader: path,
631 options: query ? query.slice(1) : undefined
632 };
633 });
634 scheme = getScheme(unresolvedResource);
635 } else {
636 unresolvedResource = requestWithoutMatchResource;
637 elements = EMPTY_ELEMENTS;
638 }
639 } else {
640 unresolvedResource = request;
641 elements = EMPTY_ELEMENTS;
642 }
643
644 /** @type {ResolveContext} */
645 const resolveContext = {
646 fileDependencies,
647 missingDependencies,
648 contextDependencies
649 };
650
651 /** @type {ResourceDataWithData} */
652 let resourceData;
653
654 /** @type {undefined | LoaderItem[]} */
655 let loaders;
656
657 const continueCallback = needCalls(2, (err) => {
658 if (err) return callback(err);
659
660 // translate option idents
661 try {
662 for (const item of /** @type {LoaderItem[]} */ (loaders)) {
663 if (typeof item.options === "string" && item.options[0] === "?") {
664 const ident = item.options.slice(1);
665 if (ident === "[[missing ident]]") {
666 throw new Error(
667 "No ident is provided by referenced loader. " +
668 "When using a function for Rule.use in config you need to " +
669 "provide an 'ident' property for referenced loader options."
670 );
671 }
672 item.options = this.ruleSet.references.get(ident);
673 if (item.options === undefined) {
674 throw new Error(
675 "Invalid ident is provided by referenced loader"
676 );
677 }
678 item.ident = ident;
679 }
680 }
681 } catch (identErr) {
682 return callback(/** @type {Error} */ (identErr));
683 }
684
685 if (!resourceData) {
686 // ignored
687 return callback(null, dependencies[0].createIgnoredModule(context));
688 }
689
690 const userRequest =
691 (matchResourceData !== undefined
692 ? `${matchResourceData.resource}!=!`
693 : "") +
694 stringifyLoadersAndResource(
695 /** @type {LoaderItem[]} */ (loaders),
696 resourceData.resource
697 );
698
699 /** @type {ModuleSettings} */
700 const settings = {};
701 /** @type {LoaderItem[]} */
702 const useLoadersPost = [];
703 /** @type {LoaderItem[]} */
704 const useLoaders = [];
705 /** @type {LoaderItem[]} */
706 const useLoadersPre = [];
707
708 // handle .webpack[] suffix
709 /** @type {string} */
710 let resource;
711 /** @type {RegExpExecArray | null} */
712 let match;
713 if (
714 matchResourceData &&
715 typeof (resource = matchResourceData.resource) === "string" &&
716 (match = /\.webpack\[([^\]]+)\]$/.exec(resource))
717 ) {
718 settings.type = match[1];
719 matchResourceData.resource = matchResourceData.resource.slice(
720 0,
721 -settings.type.length - 10
722 );
723 } else {
724 settings.type = JAVASCRIPT_MODULE_TYPE_AUTO;
725 const resourceDataForRules = matchResourceData || resourceData;
726
727 const result = this.ruleSet.exec({
728 resource: resourceDataForRules.path,
729 realResource: resourceData.path,
730 resourceQuery: resourceDataForRules.query,
731 resourceFragment: resourceDataForRules.fragment,
732 scheme,
733 phase,
734 attributes,
735 mimetype: matchResourceData
736 ? ""
737 : resourceData.data.mimetype || "",
738 dependency: dependencyType,
739 descriptionData: matchResourceData
740 ? undefined
741 : resourceData.data.descriptionFileData,
742 issuer: contextInfo.issuer,
743 compiler: contextInfo.compiler,
744 issuerLayer: contextInfo.issuerLayer || ""
745 });
746 for (const r of result) {
747 // https://github.com/webpack/webpack/issues/16466
748 // if a request exists PrePostAutoLoaders, should disable modifying Rule.type
749 if (r.type === "type" && noPrePostAutoLoaders) {
750 continue;
751 }
752 if (r.type === "use") {
753 if (!noAutoLoaders && !noPrePostAutoLoaders) {
754 useLoaders.push(r.value);
755 }
756 } else if (r.type === "use-post") {
757 if (!noPrePostAutoLoaders) {
758 useLoadersPost.push(r.value);
759 }
760 } else if (r.type === "use-pre") {
761 if (!noPreAutoLoaders && !noPrePostAutoLoaders) {
762 useLoadersPre.push(r.value);
763 }
764 } else if (
765 typeof r.value === "object" &&
766 r.value !== null &&
767 typeof settings[
768 /** @type {keyof ModuleSettings} */
769 (r.type)
770 ] === "object" &&
771 settings[/** @type {keyof ModuleSettings} */ (r.type)] !== null
772 ) {
773 const type = /** @type {keyof ModuleSettings} */ (r.type);
774 settings[type] = cachedCleverMerge(settings[type], r.value);
775 } else {
776 const type = /** @type {keyof ModuleSettings} */ (r.type);
777 settings[type] = r.value;
778 }
779 }
780 }
781
782 /** @type {undefined | LoaderItem[]} */
783 let postLoaders;
784 /** @type {undefined | LoaderItem[]} */
785 let normalLoaders;
786 /** @type {undefined | LoaderItem[]} */
787 let preLoaders;
788
789 const continueCallback = needCalls(3, (err) => {
790 if (err) {
791 return callback(err);
792 }
793 const allLoaders = /** @type {LoaderItem[]} */ (postLoaders);
794 if (matchResourceData === undefined) {
795 for (const loader of /** @type {LoaderItem[]} */ (loaders)) {
796 allLoaders.push(loader);
797 }
798 for (const loader of /** @type {LoaderItem[]} */ (
799 normalLoaders
800 )) {
801 allLoaders.push(loader);
802 }
803 } else {
804 for (const loader of /** @type {LoaderItem[]} */ (
805 normalLoaders
806 )) {
807 allLoaders.push(loader);
808 }
809 for (const loader of /** @type {LoaderItem[]} */ (loaders)) {
810 allLoaders.push(loader);
811 }
812 }
813 for (const loader of /** @type {LoaderItem[]} */ (preLoaders)) {
814 allLoaders.push(loader);
815 }
816 const type = /** @type {NormalModuleTypes} */ (settings.type);
817 const resolveOptions = settings.resolve;
818 const layer = settings.layer;
819
820 try {
821 Object.assign(data.createData, {
822 layer:
823 layer === undefined ? contextInfo.issuerLayer || null : layer,
824 request: stringifyLoadersAndResource(
825 allLoaders,
826 resourceData.resource
827 ),
828 userRequest,
829 rawRequest: request,
830 loaders: allLoaders,
831 resource: resourceData.resource,
832 context:
833 resourceData.context || getContext(resourceData.resource),
834 matchResource: matchResourceData
835 ? matchResourceData.resource
836 : undefined,
837 resourceResolveData: resourceData.data,
838 settings,
839 type,
840 parser: this.getParser(type, settings.parser),
841 parserOptions: settings.parser,
842 generator: this.getGenerator(type, settings.generator),
843 generatorOptions: settings.generator,
844 resolveOptions,
845 extractSourceMap: settings.extractSourceMap || false
846 });
847 } catch (createDataErr) {
848 return callback(/** @type {Error} */ (createDataErr));
849 }
850 callback();
851 });
852 this.resolveRequestArray(
853 contextInfo,
854 this.context,
855 useLoadersPost,
856 loaderResolver,
857 resolveContext,
858 (err, result) => {
859 postLoaders = result;
860 continueCallback(err);
861 }
862 );
863 this.resolveRequestArray(
864 contextInfo,
865 this.context,
866 useLoaders,
867 loaderResolver,
868 resolveContext,
869 (err, result) => {
870 normalLoaders = result;
871 continueCallback(err);
872 }
873 );
874 this.resolveRequestArray(
875 contextInfo,
876 this.context,
877 useLoadersPre,
878 loaderResolver,
879 resolveContext,
880 (err, result) => {
881 preLoaders = result;
882 continueCallback(err);
883 }
884 );
885 });
886
887 this.resolveRequestArray(
888 contextInfo,
889 contextScheme ? this.context : context,
890 /** @type {LoaderItem[]} */ (elements),
891 loaderResolver,
892 resolveContext,
893 (err, result) => {
894 if (err) return continueCallback(err);
895 loaders = result;
896 continueCallback();
897 }
898 );
899
900 /**
901 * Processes the provided string.
902 * @param {string} context context
903 */
904 const defaultResolve = (context) => {
905 if (/^(?:$|\?)/.test(unresolvedResource)) {
906 resourceData = {
907 ...cacheParseResource(unresolvedResource),
908 resource: unresolvedResource,
909 data: {}
910 };
911 continueCallback();
912 }
913
914 // resource without scheme and with path
915 else {
916 const normalResolver = this.getResolver(
917 "normal",
918 dependencyType
919 ? cachedSetProperty(
920 resolveOptions || EMPTY_RESOLVE_OPTIONS,
921 "dependencyType",
922 dependencyType
923 )
924 : resolveOptions
925 );
926 this.resolveResource(
927 contextInfo,
928 context,
929 escapeHashInPathRequest(unresolvedResource),
930 normalResolver,
931 resolveContext,
932 (err, _resolvedResource, resolvedResourceResolveData) => {
933 if (err) return continueCallback(err);
934 if (_resolvedResource !== false) {
935 const resolvedResource =
936 /** @type {string} */
937 (_resolvedResource);
938 resourceData = {
939 ...cacheParseResource(resolvedResource),
940 resource: resolvedResource,
941 data:
942 /** @type {ResolveRequest} */
943 (resolvedResourceResolveData)
944 };
945 }
946 continueCallback();
947 }
948 );
949 }
950 };
951
952 // resource with scheme
953 if (scheme) {
954 resourceData = {
955 resource: unresolvedResource,
956 data: {},
957 path: undefined,
958 query: undefined,
959 fragment: undefined,
960 context: undefined
961 };
962 this.hooks.resolveForScheme
963 .for(scheme)
964 .callAsync(resourceData, data, (err) => {
965 if (err) return continueCallback(err);
966 continueCallback();
967 });
968 }
969
970 // resource within scheme
971 else if (contextScheme) {
972 resourceData = {
973 resource: unresolvedResource,
974 data: {},
975 path: undefined,
976 query: undefined,
977 fragment: undefined,
978 context: undefined
979 };
980 this.hooks.resolveInScheme
981 .for(contextScheme)
982 .callAsync(resourceData, data, (err, handled) => {
983 if (err) return continueCallback(err);
984 if (!handled) return defaultResolve(this.context);
985 continueCallback();
986 });
987 }
988
989 // resource without scheme and without path
990 else {
991 defaultResolve(context);
992 }
993 }
994 );
995 }
996
997 cleanupForCache() {
998 for (const module of this._restoredUnsafeCacheEntries) {
999 ChunkGraph.clearChunkGraphForModule(module);
1000 ModuleGraph.clearModuleGraphForModule(module);
1001 module.cleanupForCache();
1002 }
1003 }
1004
1005 /**
1006 * Processes the provided data.
1007 * @param {ModuleFactoryCreateData} data data object
1008 * @param {ModuleFactoryCallback} callback callback
1009 * @returns {void}
1010 */
1011 create(data, callback) {
1012 const dependencies = /** @type {ModuleDependency[]} */ (data.dependencies);
1013 const context = data.context || this.context;
1014 const resolveOptions = data.resolveOptions || EMPTY_RESOLVE_OPTIONS;
1015 const dependency = dependencies[0];
1016 const request = dependency.request;
1017 const attributes =
1018 /** @type {ModuleDependency & { attributes: ImportAttributes }} */
1019 (dependency).attributes;
1020 const phase =
1021 typeof (
1022 /** @type {ModuleDependency & { phase?: ImportPhaseType }} */
1023 (dependency).phase
1024 ) === "number"
1025 ? ImportPhaseUtils.stringify(
1026 /** @type {ModuleDependency & { phase?: ImportPhaseType }} */
1027 (dependency).phase
1028 )
1029 : "evaluation";
1030 const dependencyType = dependency.category || "";
1031 const contextInfo = data.contextInfo;
1032 /** @type {FileSystemDependencies} */
1033 const fileDependencies = new LazySet();
1034 /** @type {FileSystemDependencies} */
1035 const missingDependencies = new LazySet();
1036 /** @type {FileSystemDependencies} */
1037 const contextDependencies = new LazySet();
1038 /** @type {ResolveData} */
1039 const resolveData = {
1040 contextInfo,
1041 resolveOptions,
1042 context,
1043 request,
1044 phase,
1045 attributes,
1046 dependencies,
1047 dependencyType,
1048 fileDependencies,
1049 missingDependencies,
1050 contextDependencies,
1051 createData: {},
1052 cacheable: true
1053 };
1054 this.hooks.beforeResolve.callAsync(resolveData, (err, result) => {
1055 if (err) {
1056 return callback(err, {
1057 fileDependencies,
1058 missingDependencies,
1059 contextDependencies,
1060 cacheable: false
1061 });
1062 }
1063
1064 // Ignored
1065 if (result === false) {
1066 /** @type {ModuleFactoryResult} * */
1067 const factoryResult = {
1068 fileDependencies,
1069 missingDependencies,
1070 contextDependencies,
1071 cacheable: resolveData.cacheable
1072 };
1073
1074 if (resolveData.ignoredModule) {
1075 factoryResult.module = resolveData.ignoredModule;
1076 }
1077
1078 return callback(null, factoryResult);
1079 }
1080
1081 if (typeof result === "object") {
1082 throw new Error(
1083 deprecationChangedHookMessage(
1084 "beforeResolve",
1085 this.hooks.beforeResolve
1086 )
1087 );
1088 }
1089
1090 this.hooks.factorize.callAsync(resolveData, (err, module) => {
1091 if (err) {
1092 return callback(err, {
1093 fileDependencies,
1094 missingDependencies,
1095 contextDependencies,
1096 cacheable: false
1097 });
1098 }
1099
1100 /** @type {ModuleFactoryResult} * */
1101 const factoryResult = {
1102 module,
1103 fileDependencies,
1104 missingDependencies,
1105 contextDependencies,
1106 cacheable: resolveData.cacheable
1107 };
1108
1109 callback(null, factoryResult);
1110 });
1111 });
1112 }
1113
1114 /**
1115 * Processes the provided context info.
1116 * @param {ModuleFactoryCreateDataContextInfo} contextInfo context info
1117 * @param {string} context context
1118 * @param {string} unresolvedResource unresolved resource
1119 * @param {ResolverWithOptions} resolver resolver
1120 * @param {ResolveContext} resolveContext resolver context
1121 * @param {(err: null | Error, res?: string | false, req?: ResolveRequest) => void} callback callback
1122 */
1123 resolveResource(
1124 contextInfo,
1125 context,
1126 unresolvedResource,
1127 resolver,
1128 resolveContext,
1129 callback
1130 ) {
1131 resolver.resolve(
1132 contextInfo,
1133 context,
1134 unresolvedResource,
1135 resolveContext,
1136 (err, resolvedResource, resolvedResourceResolveData) => {
1137 if (err) {
1138 return this._resolveResourceErrorHints(
1139 err,
1140 contextInfo,
1141 context,
1142 unresolvedResource,
1143 resolver,
1144 resolveContext,
1145 (err2, hints) => {
1146 if (err2) {
1147 err.message += `
1148A fatal error happened during resolving additional hints for this error: ${err2.message}`;
1149 err.stack += `
1150
1151A fatal error happened during resolving additional hints for this error:
1152${err2.stack}`;
1153 return callback(err);
1154 }
1155 if (hints && hints.length > 0) {
1156 err.message += `
1157${hints.join("\n\n")}`;
1158 }
1159
1160 // Check if the extension is missing a leading dot (e.g. "js" instead of ".js")
1161 let appendResolveExtensionsHint = false;
1162 const specifiedExtensions = [...resolver.options.extensions];
1163 const expectedExtensions = specifiedExtensions.map(
1164 (extension) => {
1165 if (LEADING_DOT_EXTENSION_REGEX.test(extension)) {
1166 appendResolveExtensionsHint = true;
1167 return `.${extension}`;
1168 }
1169 return extension;
1170 }
1171 );
1172 if (appendResolveExtensionsHint) {
1173 err.message += `\nDid you miss the leading dot in 'resolve.extensions'? Did you mean '${JSON.stringify(
1174 expectedExtensions
1175 )}' instead of '${JSON.stringify(specifiedExtensions)}'?`;
1176 }
1177
1178 callback(err);
1179 }
1180 );
1181 }
1182 callback(err, resolvedResource, resolvedResourceResolveData);
1183 }
1184 );
1185 }
1186
1187 /**
1188 * Resolve resource error hints.
1189 * @param {Error} error error
1190 * @param {ModuleFactoryCreateDataContextInfo} contextInfo context info
1191 * @param {string} context context
1192 * @param {string} unresolvedResource unresolved resource
1193 * @param {ResolverWithOptions} resolver resolver
1194 * @param {ResolveContext} resolveContext resolver context
1195 * @param {Callback<string[]>} callback callback
1196 * @private
1197 */
1198 _resolveResourceErrorHints(
1199 error,
1200 contextInfo,
1201 context,
1202 unresolvedResource,
1203 resolver,
1204 resolveContext,
1205 callback
1206 ) {
1207 asyncLib.parallel(
1208 [
1209 (callback) => {
1210 if (!resolver.options.fullySpecified) return callback();
1211 resolver
1212 .withOptions({
1213 fullySpecified: false
1214 })
1215 .resolve(
1216 contextInfo,
1217 context,
1218 unresolvedResource,
1219 resolveContext,
1220 (err, resolvedResource) => {
1221 if (!err && resolvedResource) {
1222 const resource = parseResource(resolvedResource).path.replace(
1223 /^.*[\\/]/,
1224 ""
1225 );
1226 return callback(
1227 null,
1228 `Did you mean '${resource}'?
1229BREAKING CHANGE: The request '${unresolvedResource}' failed to resolve only because it was resolved as fully specified
1230(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"').
1231The extension in the request is mandatory for it to be fully specified.
1232Add the extension to the request.`
1233 );
1234 }
1235 callback();
1236 }
1237 );
1238 },
1239 (callback) => {
1240 if (!resolver.options.enforceExtension) return callback();
1241 resolver
1242 .withOptions({
1243 enforceExtension: false,
1244 extensions: []
1245 })
1246 .resolve(
1247 contextInfo,
1248 context,
1249 unresolvedResource,
1250 resolveContext,
1251 (err, resolvedResource) => {
1252 if (!err && resolvedResource) {
1253 let hint = "";
1254 const match = /\.[^.]+(?:\?|$)/.exec(unresolvedResource);
1255 if (match) {
1256 const fixedRequest = unresolvedResource.replace(
1257 /(\.[^.]+)(\?|$)/,
1258 "$2"
1259 );
1260 hint = resolver.options.extensions.has(match[1])
1261 ? `Did you mean '${fixedRequest}'?`
1262 : `Did you mean '${fixedRequest}'? Also note that '${match[1]}' is not in 'resolve.extensions' yet and need to be added for this to work?`;
1263 } else {
1264 hint =
1265 "Did you mean to omit the extension or to remove 'resolve.enforceExtension'?";
1266 }
1267 return callback(
1268 null,
1269 `The request '${unresolvedResource}' failed to resolve only because 'resolve.enforceExtension' was specified.
1270${hint}
1271Including the extension in the request is no longer possible. Did you mean to enforce including the extension in requests with 'resolve.extensions: []' instead?`
1272 );
1273 }
1274 callback();
1275 }
1276 );
1277 },
1278 (callback) => {
1279 if (
1280 /^\.\.?\//.test(unresolvedResource) ||
1281 resolver.options.preferRelative
1282 ) {
1283 return callback();
1284 }
1285 resolver.resolve(
1286 contextInfo,
1287 context,
1288 `./${unresolvedResource}`,
1289 resolveContext,
1290 (err, resolvedResource) => {
1291 if (err || !resolvedResource) return callback();
1292 const moduleDirectories = resolver.options.modules
1293 .map((m) => (Array.isArray(m) ? m.join(", ") : m))
1294 .join(", ");
1295 callback(
1296 null,
1297 `Did you mean './${unresolvedResource}'?
1298Requests that should resolve in the current directory need to start with './'.
1299Requests that start with a name are treated as module requests and resolve within module directories (${moduleDirectories}).
1300If 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.`
1301 );
1302 }
1303 );
1304 }
1305 ],
1306 (err, hints) => {
1307 if (err) return callback(err);
1308 callback(null, /** @type {string[]} */ (hints).filter(Boolean));
1309 }
1310 );
1311 }
1312
1313 /**
1314 * Resolves request array.
1315 * @param {ModuleFactoryCreateDataContextInfo} contextInfo context info
1316 * @param {string} context context
1317 * @param {LoaderItem[]} array array
1318 * @param {ResolverWithOptions} resolver resolver
1319 * @param {ResolveContext} resolveContext resolve context
1320 * @param {Callback<LoaderItem[]>} callback callback
1321 * @returns {void} result
1322 */
1323 resolveRequestArray(
1324 contextInfo,
1325 context,
1326 array,
1327 resolver,
1328 resolveContext,
1329 callback
1330 ) {
1331 // LoaderItem
1332 if (array.length === 0) return callback(null, array);
1333 asyncLib.map(
1334 array,
1335 /**
1336 * Handles the callback logic for this hook.
1337 * @param {LoaderItem} item item
1338 * @param {Callback<LoaderItem>} callback callback
1339 */
1340 (item, callback) => {
1341 resolver.resolve(
1342 contextInfo,
1343 context,
1344 item.loader,
1345 resolveContext,
1346 (err, result, resolveRequest) => {
1347 if (
1348 err &&
1349 /^[^/]*$/.test(item.loader) &&
1350 !item.loader.endsWith("-loader")
1351 ) {
1352 return resolver.resolve(
1353 contextInfo,
1354 context,
1355 `${item.loader}-loader`,
1356 resolveContext,
1357 (err2) => {
1358 if (!err2) {
1359 err.message =
1360 `${err.message}\n` +
1361 "BREAKING CHANGE: It's no longer allowed to omit the '-loader' suffix when using loaders.\n" +
1362 ` You need to specify '${item.loader}-loader' instead of '${item.loader}',\n` +
1363 " see https://webpack.js.org/migrate/3/#automatic-loader-module-name-extension-removed";
1364 }
1365 callback(err);
1366 }
1367 );
1368 }
1369 if (err) return callback(err);
1370
1371 const parsedResult = this._parseResourceWithoutFragment(
1372 /** @type {string} */
1373 (result)
1374 );
1375
1376 const type = /\.mjs$/i.test(parsedResult.path)
1377 ? "module"
1378 : /\.cjs$/i.test(parsedResult.path)
1379 ? "commonjs"
1380 : /** @type {ResolveRequest} */
1381 (resolveRequest).descriptionFileData === undefined
1382 ? undefined
1383 : /** @type {string} */
1384 (
1385 /** @type {ResolveRequest} */
1386 (resolveRequest).descriptionFileData.type
1387 );
1388 /** @type {LoaderItem} */
1389 const resolved = {
1390 loader: parsedResult.path,
1391 type,
1392 options:
1393 item.options === undefined
1394 ? parsedResult.query
1395 ? parsedResult.query.slice(1)
1396 : undefined
1397 : item.options,
1398 ident: item.options === undefined ? undefined : item.ident
1399 };
1400
1401 return callback(null, resolved);
1402 }
1403 );
1404 },
1405 (err, value) => {
1406 callback(
1407 /** @type {Error | null} */ (err),
1408 /** @type {(LoaderItem)[]} */ (value)
1409 );
1410 }
1411 );
1412 }
1413
1414 /**
1415 * Returns parser.
1416 * @template {string} T
1417 * @param {T} type type
1418 * @param {ParserOptions} parserOptions parser options
1419 * @returns {ParserByType[T]} parser
1420 */
1421 getParser(type, parserOptions = EMPTY_PARSER_OPTIONS) {
1422 let cache = this.parserCache.get(type);
1423
1424 if (cache === undefined) {
1425 cache = new WeakMap();
1426 this.parserCache.set(type, cache);
1427 }
1428
1429 let parser = cache.get(parserOptions);
1430
1431 if (parser === undefined) {
1432 parser = this.createParser(type, parserOptions);
1433 cache.set(parserOptions, parser);
1434 }
1435
1436 return /** @type {ParserByType[T]} */ (parser);
1437 }
1438
1439 /**
1440 * Creates a parser from the provided type.
1441 * @template {string} T
1442 * @param {T} type type
1443 * @param {ParserOptions} parserOptions parser options
1444 * @returns {ParserByType[T]} parser
1445 */
1446 createParser(type, parserOptions = {}) {
1447 parserOptions = mergeGlobalOptions(
1448 this._globalParserOptions,
1449 type,
1450 parserOptions
1451 );
1452 const parser = this.hooks.createParser.for(type).call(parserOptions);
1453 if (!parser) {
1454 throw new Error(`No parser registered for ${type}`);
1455 }
1456 this.hooks.parser.for(type).call(parser, parserOptions);
1457 return /** @type {ParserByType[T]} */ (parser);
1458 }
1459
1460 /**
1461 * Returns generator.
1462 * @template {string} T
1463 * @param {T} type type of generator
1464 * @param {GeneratorOptions} generatorOptions generator options
1465 * @returns {GeneratorByType[T]} generator
1466 */
1467 getGenerator(type, generatorOptions = EMPTY_GENERATOR_OPTIONS) {
1468 let cache = this.generatorCache.get(type);
1469
1470 if (cache === undefined) {
1471 cache = new WeakMap();
1472 this.generatorCache.set(type, cache);
1473 }
1474
1475 let generator = cache.get(generatorOptions);
1476
1477 if (generator === undefined) {
1478 generator = this.createGenerator(type, generatorOptions);
1479 cache.set(generatorOptions, generator);
1480 }
1481
1482 return /** @type {GeneratorByType[T]} */ (generator);
1483 }
1484
1485 /**
1486 * Creates a generator.
1487 * @template {string} T
1488 * @param {T} type type of generator
1489 * @param {GeneratorOptions} generatorOptions generator options
1490 * @returns {GeneratorByType[T]} generator
1491 */
1492 createGenerator(type, generatorOptions = {}) {
1493 generatorOptions = mergeGlobalOptions(
1494 this._globalGeneratorOptions,
1495 type,
1496 generatorOptions
1497 );
1498 const generator = this.hooks.createGenerator
1499 .for(type)
1500 .call(generatorOptions);
1501 if (!generator) {
1502 throw new Error(`No generator registered for ${type}`);
1503 }
1504 this.hooks.generator.for(type).call(generator, generatorOptions);
1505 return /** @type {GeneratorByType[T]} */ (generator);
1506 }
1507
1508 /**
1509 * Returns the resolver.
1510 * @param {Parameters<ResolverFactory["get"]>[0]} type type of resolver
1511 * @param {Parameters<ResolverFactory["get"]>[1]=} resolveOptions options
1512 * @returns {ReturnType<ResolverFactory["get"]>} the resolver
1513 */
1514 getResolver(type, resolveOptions) {
1515 return this.resolverFactory.get(type, resolveOptions);
1516 }
1517}
1518
1519module.exports = NormalModuleFactory;
Note: See TracBrowser for help on using the repository browser.