source: frontend/node_modules/webpack/lib/NormalModule.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: 56.6 KB
RevLine 
[9af201e]1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6"use strict";
7
8const querystring = require("querystring");
9const { getContext, runLoaders } = require("loader-runner");
10const {
11 AsyncSeriesBailHook,
12 HookMap,
13 SyncHook,
14 SyncWaterfallHook
15} = require("tapable");
16const {
17 CachedSource,
18 OriginalSource,
19 RawSource,
20 SourceMapSource
21} = require("webpack-sources");
22const Compilation = require("./Compilation");
23const Module = require("./Module");
24const ModuleGraphConnection = require("./ModuleGraphConnection");
25const { JAVASCRIPT_MODULE_TYPE_AUTO } = require("./ModuleTypeConstants");
26const RuntimeGlobals = require("./RuntimeGlobals");
27const HookWebpackError = require("./errors/HookWebpackError");
28const ModuleBuildError = require("./errors/ModuleBuildError");
29const ModuleError = require("./errors/ModuleError");
30const ModuleParseError = require("./errors/ModuleParseError");
31const ModuleWarning = require("./errors/ModuleWarning");
32const NonErrorEmittedError = require("./errors/NonErrorEmittedError");
33const UnhandledSchemeError = require("./errors/UnhandledSchemeError");
34const LazySet = require("./util/LazySet");
35const { isSubset } = require("./util/SetHelpers");
36const { getScheme } = require("./util/URLAbsoluteSpecifier");
37const {
38 compareLocations,
39 compareSelect,
40 concatComparators,
41 keepOriginalOrder,
42 sortWithSourceOrder
43} = require("./util/comparators");
44const createHash = require("./util/createHash");
45const { createFakeHook } = require("./util/deprecation");
46const formatLocation = require("./util/formatLocation");
47const { join } = require("./util/fs");
48const {
49 absolutify,
50 contextify,
51 makePathsRelative
52} = require("./util/identifier");
53const makeSerializable = require("./util/makeSerializable");
54const memoize = require("./util/memoize");
55const parseJson = require("./util/parseJson");
56
57/** @typedef {import("enhanced-resolve").ResolveContext} ResolveContext */
58/** @typedef {import("enhanced-resolve").ResolveRequest} ResolveRequest */
59/** @typedef {import("webpack-sources").Source} Source */
60/** @typedef {import("webpack-sources").RawSourceMap} RawSourceMap */
61/** @typedef {import("../declarations/WebpackOptions").ResolveOptions} ResolveOptions */
62/** @typedef {import("../declarations/WebpackOptions").NoParse} NoParse */
63/** @typedef {import("./config/defaults").WebpackOptionsNormalizedWithDefaults} WebpackOptions */
64/** @typedef {import("./Dependency")} Dependency */
65/** @typedef {import("./Dependency").UpdateHashContext} UpdateHashContext */
66/** @typedef {import("./Generator")} Generator */
67/** @typedef {import("./Generator").GenerateErrorFn} GenerateErrorFn */
68/** @typedef {import("./Module").BuildInfo} BuildInfo */
69/** @typedef {import("./Module").FileSystemDependencies} FileSystemDependencies */
70/** @typedef {import("./Module").BuildMeta} BuildMeta */
71/** @typedef {import("./Module").CodeGenerationContext} CodeGenerationContext */
72/** @typedef {import("./Module").CodeGenerationResult} CodeGenerationResult */
73/** @typedef {import("./Module").CodeGenerationResultData} CodeGenerationResultData */
74/** @typedef {import("./Module").ConcatenationBailoutReasonContext} ConcatenationBailoutReasonContext */
75/** @typedef {import("./Module").KnownBuildInfo} KnownBuildInfo */
76/** @typedef {import("./Module").LibIdentOptions} LibIdentOptions */
77/** @typedef {import("./Module").LibIdent} LibIdent */
78/** @typedef {import("./Module").NameForCondition} NameForCondition */
79/** @typedef {import("./Module").NeedBuildContext} NeedBuildContext */
80/** @typedef {import("./Module").NeedBuildCallback} NeedBuildCallback */
81/** @typedef {import("./Module").BuildCallback} BuildCallback */
82/** @typedef {import("./Module").RuntimeRequirements} RuntimeRequirements */
83/** @typedef {import("./Module").Sources} Sources */
84/** @typedef {import("./Module").SourceType} SourceType */
85/** @typedef {import("./Module").SourceTypes} SourceTypes */
86/** @typedef {import("./Module").UnsafeCacheData} UnsafeCacheData */
87/** @typedef {import("./ModuleGraph")} ModuleGraph */
88/** @typedef {import("./ModuleGraphConnection").ConnectionState} ConnectionState */
89/** @typedef {Iterator<SideEffectsWalk, ConnectionState, ConnectionState>} SideEffectsWalk */
90/** @typedef {import("./NormalModuleFactory")} NormalModuleFactory */
91/** @typedef {import("./NormalModuleFactory").NormalModuleTypes} NormalModuleTypes */
92/** @typedef {import("./NormalModuleFactory").ParserByType} ParserByType */
93/** @typedef {import("./NormalModuleFactory").ParserOptionsByType} ParserOptionsByType */
94/** @typedef {import("./NormalModuleFactory").GeneratorByType} GeneratorByType */
95/** @typedef {import("./NormalModuleFactory").GeneratorOptionsByType} GeneratorOptionsByType */
96/** @typedef {import("./NormalModuleFactory").ResourceSchemeData} ResourceSchemeData */
97/** @typedef {import("./Parser")} Parser */
98/** @typedef {import("./Parser").PreparsedAst} PreparsedAst */
99/** @typedef {import("./RequestShortener")} RequestShortener */
100/** @typedef {import("./ResolverFactory").ResolverWithOptions} ResolverWithOptions */
101/** @typedef {import("./serialization/ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
102/** @typedef {import("./serialization/ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */
103/** @typedef {import("./util/Hash")} Hash */
104/** @typedef {import("./util/fs").InputFileSystem} InputFileSystem */
105/** @typedef {import("../declarations/WebpackOptions").HashFunction} HashFunction */
106/** @typedef {import("./util/identifier").AssociatedObjectForCache} AssociatedObjectForCache */
107/**
108 * @template T
109 * @typedef {import("./util/deprecation").FakeHook<T>} FakeHook
110 */
111
112/** @typedef {{ [k: string]: EXPECTED_ANY }} ParserOptions */
113/** @typedef {{ [k: string]: EXPECTED_ANY }} GeneratorOptions */
114
115/**
116 * @template T
117 * @typedef {import("../declarations/LoaderContext").LoaderContext<T>} LoaderContext
118 */
119
120/**
121 * @template T
122 * @typedef {import("../declarations/LoaderContext").NormalModuleLoaderContext<T>} NormalModuleLoaderContext
123 */
124
125/** @typedef {(content: string) => boolean} NoParseFn */
126
127const getInvalidDependenciesModuleWarning = memoize(() =>
128 require("./errors/InvalidDependenciesModuleWarning")
129);
130
131const getExtractSourceMap = memoize(() => require("./util/extractSourceMap"));
132
133const getValidate = memoize(() => require("schema-utils").validate);
134
135const getHarmonyImportSideEffectDependency = memoize(() =>
136 require("./dependencies/HarmonyImportSideEffectDependency")
137);
138
139/**
140 * @param {NormalModule} mod the module
141 * @param {ModuleGraph} moduleGraph the module graph
142 * @param {Dependency} dep the dep that triggered the bailout
143 */
144const recordSideEffectsBailout = (mod, moduleGraph, dep) => {
145 if (mod._addedSideEffectsBailout === undefined) {
146 mod._addedSideEffectsBailout = new WeakSet();
147 } else if (mod._addedSideEffectsBailout.has(moduleGraph)) {
148 return;
149 }
150 mod._addedSideEffectsBailout.add(moduleGraph);
151 moduleGraph
152 .getOptimizationBailout(mod)
153 .push(
154 () =>
155 `Dependency (${dep.type}) with side effects at ${formatLocation(dep.loc)}`
156 );
157};
158
159/**
160 * Generator form of `getSideEffectsConnectionState` — descends through
161 * `HarmonyImportSideEffectDependency` via `yield` so the trampoline in
162 * `getSideEffectsConnectionState` can drive the walk iteratively (#20986).
163 * @param {NormalModule} mod the module being evaluated
164 * @param {ModuleGraph} moduleGraph the module graph
165 * @returns {SideEffectsWalk} the generator
166 */
167function* walkSideEffects(mod, moduleGraph) {
168 if (mod.factoryMeta !== undefined) {
169 if (mod.factoryMeta.sideEffectFree) return false;
170 if (mod.factoryMeta.sideEffectFree === false) return true;
171 }
172 if (!(mod.buildMeta !== undefined && mod.buildMeta.sideEffectFree)) {
173 return true;
174 }
175 if (mod._isEvaluatingSideEffects) {
176 return ModuleGraphConnection.CIRCULAR_CONNECTION;
177 }
178
179 const SideEffectDep = getHarmonyImportSideEffectDependency();
180 mod._isEvaluatingSideEffects = true;
181 /** @type {ConnectionState} */
182 let current = false;
183
184 for (const dep of mod.dependencies) {
185 /** @type {ConnectionState} */
186 let state;
187 if (dep instanceof SideEffectDep) {
188 const refModule = moduleGraph.getModule(dep);
189 if (!refModule) {
190 state = true;
191 } else if (refModule instanceof NormalModule) {
192 state = yield walkSideEffects(refModule, moduleGraph);
193 } else {
194 state = refModule.getSideEffectsConnectionState(moduleGraph);
195 }
196 } else {
197 state = dep.getModuleEvaluationSideEffectsState(moduleGraph);
198 }
199
200 if (state === true) {
201 recordSideEffectsBailout(mod, moduleGraph, dep);
202 mod._isEvaluatingSideEffects = false;
203 return true;
204 }
205 if (state !== ModuleGraphConnection.CIRCULAR_CONNECTION) {
206 current = ModuleGraphConnection.addConnectionStates(current, state);
207 }
208 }
209
210 mod._isEvaluatingSideEffects = false;
211 // When caching is implemented here, make sure to not cache when
212 // at least one circular connection was folded into `current`.
213 return current;
214}
215
216const ABSOLUTE_PATH_REGEX = /^(?:[a-z]:\\|\\\\|\/)/i;
217
218/**
219 * @typedef {object} LoaderItem
220 * @property {string} loader
221 * @property {string | null | undefined | Record<string, EXPECTED_ANY>} options
222 * @property {string | null=} ident
223 * @property {string | null=} type
224 */
225
226/**
227 * @param {string} context absolute context path
228 * @param {string} source a source path
229 * @param {AssociatedObjectForCache=} associatedObjectForCache an object to which the cache will be attached
230 * @returns {string} new source path
231 */
232const contextifySourceUrl = (context, source, associatedObjectForCache) => {
233 if (source.startsWith("webpack://")) return source;
234 return `webpack://${makePathsRelative(
235 context,
236 source,
237 associatedObjectForCache
238 )}`;
239};
240
241/**
242 * @param {string} context absolute context path
243 * @param {string | RawSourceMap} sourceMap a source map
244 * @param {AssociatedObjectForCache=} associatedObjectForCache an object to which the cache will be attached
245 * @returns {string | RawSourceMap} new source map
246 */
247const contextifySourceMap = (context, sourceMap, associatedObjectForCache) => {
248 if (typeof sourceMap === "string" || !Array.isArray(sourceMap.sources)) {
249 return sourceMap;
250 }
251 const { sourceRoot } = sourceMap;
252 /** @type {(source: string) => string} */
253 const mapper = !sourceRoot
254 ? (source) => source
255 : sourceRoot.endsWith("/")
256 ? (source) =>
257 source.startsWith("/")
258 ? `${sourceRoot.slice(0, -1)}${source}`
259 : `${sourceRoot}${source}`
260 : (source) =>
261 source.startsWith("/")
262 ? `${sourceRoot}${source}`
263 : `${sourceRoot}/${source}`;
264 const newSources = sourceMap.sources.map((source) =>
265 contextifySourceUrl(context, mapper(source), associatedObjectForCache)
266 );
267 return {
268 ...sourceMap,
269 file: "x",
270 sourceRoot: undefined,
271 sources: newSources
272 };
273};
274
275/**
276 * @param {string | Buffer} input the input
277 * @returns {string} the converted string
278 */
279const asString = (input) => {
280 if (Buffer.isBuffer(input)) {
281 return input.toString("utf8");
282 }
283 return input;
284};
285
286/**
287 * @param {string | Buffer} input the input
288 * @returns {Buffer} the converted buffer
289 */
290const asBuffer = (input) => {
291 if (!Buffer.isBuffer(input)) {
292 return Buffer.from(input, "utf8");
293 }
294 return input;
295};
296
297/** @typedef {[string | Buffer, string | RawSourceMap | undefined, PreparsedAst | undefined]} Result */
298
299/** @typedef {LoaderContext<EXPECTED_ANY>} AnyLoaderContext */
300
301/**
302 * @deprecated Use the `readResource` hook instead.
303 * @typedef {HookMap<FakeHook<AsyncSeriesBailHook<[string, NormalModule], string | Buffer | null>>>} DeprecatedReadResourceForScheme
304 */
305
306/**
307 * @typedef {object} NormalModuleCompilationHooks
308 * @property {SyncHook<[AnyLoaderContext, NormalModule]>} loader
309 * @property {SyncHook<[LoaderItem[], NormalModule, AnyLoaderContext]>} beforeLoaders
310 * @property {SyncHook<[NormalModule]>} beforeParse
311 * @property {SyncHook<[NormalModule]>} beforeSnapshot
312 * @property {DeprecatedReadResourceForScheme} readResourceForScheme
313 * @property {HookMap<AsyncSeriesBailHook<[AnyLoaderContext], string | Buffer | null>>} readResource
314 * @property {SyncWaterfallHook<[Result, NormalModule]>} processResult
315 * @property {AsyncSeriesBailHook<[NormalModule, NeedBuildContext], boolean>} needBuild
316 */
317
318/**
319 * @template {NormalModuleTypes | ""} [T=NormalModuleTypes | ""]
320 * @typedef {object} NormalModuleCreateData
321 * @property {string=} layer an optional layer in which the module is
322 * @property {T} type module type. When deserializing, this is set to an empty string "".
323 * @property {string} request request string
324 * @property {string} userRequest request intended by user (without loaders from config)
325 * @property {string} rawRequest request without resolving
326 * @property {LoaderItem[]} loaders list of loaders
327 * @property {string} resource path + query of the real resource
328 * @property {(ResourceSchemeData & Partial<ResolveRequest>)=} resourceResolveData resource resolve data
329 * @property {string} context context directory for resolving
330 * @property {string=} matchResource path + query of the matched resource (virtual)
331 * @property {ParserByType[T]} parser the parser used
332 * @property {ParserOptionsByType[T]=} parserOptions the options of the parser used
333 * @property {GeneratorByType[T]} generator the generator used
334 * @property {GeneratorOptionsByType[T]=} generatorOptions the options of the generator used
335 * @property {ResolveOptions=} resolveOptions options used for resolving requests from this module
336 * @property {boolean} extractSourceMap enable/disable extracting source map
337 */
338
339/**
340 * @typedef {(resourcePath: string, getLoaderContext: (resourcePath: string) => AnyLoaderContext) => Promise<string | Buffer<ArrayBufferLike>>} ReadResource
341 */
342
343/** @type {WeakMap<Compilation, NormalModuleCompilationHooks>} */
344const compilationHooksMap = new WeakMap();
345
346class NormalModule extends Module {
347 /**
348 * @param {Compilation} compilation the compilation
349 * @returns {NormalModuleCompilationHooks} the attached hooks
350 */
351 static getCompilationHooks(compilation) {
352 if (!(compilation instanceof Compilation)) {
353 throw new TypeError(
354 "The 'compilation' argument must be an instance of Compilation"
355 );
356 }
357 let hooks = compilationHooksMap.get(compilation);
358 if (hooks === undefined) {
359 hooks = {
360 loader: new SyncHook(["loaderContext", "module"]),
361 beforeLoaders: new SyncHook(["loaders", "module", "loaderContext"]),
362 beforeParse: new SyncHook(["module"]),
363 beforeSnapshot: new SyncHook(["module"]),
364 // TODO webpack 6 deprecate
365 readResourceForScheme: new HookMap((scheme) => {
366 const hook =
367 /** @type {NormalModuleCompilationHooks} */
368 (hooks).readResource.for(scheme);
369 return createFakeHook(
370 /** @type {AsyncSeriesBailHook<[string, NormalModule], string | Buffer | null>} */ ({
371 tap: (options, fn) =>
372 hook.tap(options, (loaderContext) =>
373 fn(
374 loaderContext.resource,
375 /** @type {NormalModule} */ (loaderContext._module)
376 )
377 ),
378 tapAsync: (options, fn) =>
379 hook.tapAsync(options, (loaderContext, callback) =>
380 fn(
381 loaderContext.resource,
382 /** @type {NormalModule} */ (loaderContext._module),
383 callback
384 )
385 ),
386 tapPromise: (options, fn) =>
387 hook.tapPromise(options, (loaderContext) =>
388 fn(
389 loaderContext.resource,
390 /** @type {NormalModule} */ (loaderContext._module)
391 )
392 )
393 })
394 );
395 }),
396 readResource: new HookMap(
397 () => new AsyncSeriesBailHook(["loaderContext"])
398 ),
399 processResult: new SyncWaterfallHook(["result", "module"]),
400 needBuild: new AsyncSeriesBailHook(["module", "context"])
401 };
402 compilationHooksMap.set(
403 compilation,
404 /** @type {NormalModuleCompilationHooks} */ (hooks)
405 );
406 }
407 return /** @type {NormalModuleCompilationHooks} */ (hooks);
408 }
409
410 /**
411 * @param {NormalModuleCreateData} options options object
412 */
413 constructor({
414 layer,
415 type,
416 request,
417 userRequest,
418 rawRequest,
419 loaders,
420 resource,
421 resourceResolveData,
422 context,
423 matchResource,
424 parser,
425 parserOptions,
426 generator,
427 generatorOptions,
428 resolveOptions,
429 extractSourceMap
430 }) {
431 super(type, context || getContext(resource), layer);
432
433 // Info from Factory
434 /** @type {NormalModuleCreateData['request']} */
435 this.request = request;
436 /** @type {NormalModuleCreateData['userRequest']} */
437 this.userRequest = userRequest;
438 /** @type {NormalModuleCreateData['rawRequest']} */
439 this.rawRequest = rawRequest;
440 /** @type {boolean} */
441 this.binary = /^(?:asset|webassembly)\b/.test(type);
442 /** @type {NormalModuleCreateData['parser'] | undefined} */
443 this.parser = parser;
444 /** @type {NormalModuleCreateData['parserOptions']} */
445 this.parserOptions = parserOptions;
446 /** @type {NormalModuleCreateData['generator'] | undefined} */
447 this.generator = generator;
448 /** @type {NormalModuleCreateData['generatorOptions']} */
449 this.generatorOptions = generatorOptions;
450 /** @type {NormalModuleCreateData['resource']} */
451 this.resource = resource;
452 /** @type {NormalModuleCreateData['resourceResolveData']} */
453 this.resourceResolveData = resourceResolveData;
454 /** @type {NormalModuleCreateData['matchResource']} */
455 this.matchResource = matchResource;
456 /** @type {NormalModuleCreateData['loaders']} */
457 this.loaders = loaders;
458 if (resolveOptions !== undefined) {
459 // already declared in super class
460 /** @type {NormalModuleCreateData['resolveOptions']} */
461 this.resolveOptions = resolveOptions;
462 }
463 /** @type {NormalModuleCreateData['extractSourceMap']} */
464 this.extractSourceMap = extractSourceMap;
465
466 // Info from Build
467 /** @type {Error | null} */
468 this.error = null;
469 /**
470 * @private
471 * @type {Source | null}
472 */
473 this._source = null;
474 /**
475 * @private
476 * @type {Map<undefined | SourceType, number> | undefined}
477 */
478 this._sourceSizes = undefined;
479 /**
480 * @private
481 * @type {undefined | SourceTypes}
482 */
483 this._sourceTypes = undefined;
484 // Cache
485 /**
486 * @private
487 * @type {BuildMeta}
488 */
489 this._lastSuccessfulBuildMeta = {};
490 /**
491 * @private
492 * @type {boolean}
493 */
494 this._forceBuild = true;
495 /**
496 * @type {boolean}
497 */
498 this._isEvaluatingSideEffects = false;
499 /**
500 * @type {WeakSet<ModuleGraph> | undefined}
501 */
502 this._addedSideEffectsBailout = undefined;
503 /**
504 * @private
505 * @type {CodeGenerationResultData}
506 */
507 this._codeGeneratorData = new Map();
508 }
509
510 /**
511 * Returns the unique identifier used to reference this module.
512 * @returns {string} a unique identifier of the module
513 */
514 identifier() {
515 if (this.layer === null) {
516 if (this.type === JAVASCRIPT_MODULE_TYPE_AUTO) {
517 return this.request;
518 }
519 return `${this.type}|${this.request}`;
520 }
521 return `${this.type}|${this.request}|${this.layer}`;
522 }
523
524 /**
525 * Returns a human-readable identifier for this module.
526 * @param {RequestShortener} requestShortener the request shortener
527 * @returns {string} a user readable identifier of the module
528 */
529 readableIdentifier(requestShortener) {
530 return /** @type {string} */ (requestShortener.shorten(this.userRequest));
531 }
532
533 /**
534 * @returns {string | null} return the resource path
535 */
536 getResource() {
537 return this.matchResource || this.resource;
538 }
539
540 /**
541 * Gets the library identifier.
542 * @param {LibIdentOptions} options options
543 * @returns {LibIdent | null} an identifier for library inclusion
544 */
545 libIdent(options) {
546 let ident = contextify(
547 options.context,
548 this.userRequest,
549 options.associatedObjectForCache
550 );
551 if (this.layer) ident = `(${this.layer})/${ident}`;
552 return ident;
553 }
554
555 /**
556 * Returns the path used when matching this module against rule conditions.
557 * @returns {NameForCondition | null} absolute path which should be used for condition matching (usually the resource path)
558 */
559 nameForCondition() {
560 const resource = /** @type {string} */ (this.getResource());
561 const idx = resource.indexOf("?");
562 if (idx >= 0) return resource.slice(0, idx);
563 return resource;
564 }
565
566 /**
567 * Assuming this module is in the cache. Update the (cached) module with
568 * the fresh module from the factory. Usually updates internal references
569 * and properties.
570 * @param {Module} module fresh module
571 * @returns {void}
572 */
573 updateCacheModule(module) {
574 super.updateCacheModule(module);
575 const m = /** @type {NormalModule} */ (module);
576 this.binary = m.binary;
577 this.request = m.request;
578 this.userRequest = m.userRequest;
579 this.rawRequest = m.rawRequest;
580 this.parser = m.parser;
581 this.parserOptions = m.parserOptions;
582 this.generator = m.generator;
583 this.generatorOptions = m.generatorOptions;
584 this.resource = m.resource;
585 this.resourceResolveData = m.resourceResolveData;
586 this.context = m.context;
587 this.matchResource = m.matchResource;
588 this.loaders = m.loaders;
589 this.extractSourceMap = m.extractSourceMap;
590 }
591
592 /**
593 * Assuming this module is in the cache. Remove internal references to allow freeing some memory.
594 */
595 cleanupForCache() {
596 // Make sure to cache types and sizes before cleanup when this module has been built
597 // They are accessed by the stats and we don't want them to crash after cleanup
598 // TODO reconsider this for webpack 6
599 if (this.buildInfo) {
600 if (this._sourceTypes === undefined) this.getSourceTypes();
601 for (const type of /** @type {SourceTypes} */ (this._sourceTypes)) {
602 this.size(type);
603 }
604 }
605 super.cleanupForCache();
606 this.parser = undefined;
607 this.parserOptions = undefined;
608 this.generator = undefined;
609 this.generatorOptions = undefined;
610 }
611
612 /**
613 * Module should be unsafe cached. Get data that's needed for that.
614 * This data will be passed to restoreFromUnsafeCache later.
615 * @returns {UnsafeCacheData} cached data
616 */
617 getUnsafeCacheData() {
618 const data = super.getUnsafeCacheData();
619 data.parserOptions = this.parserOptions;
620 data.generatorOptions = this.generatorOptions;
621 return data;
622 }
623
624 /**
625 * restore unsafe cache data
626 * @param {UnsafeCacheData} unsafeCacheData data from getUnsafeCacheData
627 * @param {NormalModuleFactory} normalModuleFactory the normal module factory handling the unsafe caching
628 */
629 restoreFromUnsafeCache(unsafeCacheData, normalModuleFactory) {
630 this._restoreFromUnsafeCache(unsafeCacheData, normalModuleFactory);
631 }
632
633 /**
634 * restore unsafe cache data
635 * @param {UnsafeCacheData} unsafeCacheData data from getUnsafeCacheData
636 * @param {NormalModuleFactory} normalModuleFactory the normal module factory handling the unsafe caching
637 */
638 _restoreFromUnsafeCache(unsafeCacheData, normalModuleFactory) {
639 super._restoreFromUnsafeCache(unsafeCacheData, normalModuleFactory);
640 this.parserOptions = unsafeCacheData.parserOptions;
641 this.parser = normalModuleFactory.getParser(this.type, this.parserOptions);
642 this.generatorOptions = unsafeCacheData.generatorOptions;
643 this.generator = normalModuleFactory.getGenerator(
644 this.type,
645 this.generatorOptions
646 );
647 // we assume the generator behaves identically and keep cached sourceTypes/Sizes
648 }
649
650 /**
651 * @param {string} context the compilation context
652 * @param {string} name the asset name
653 * @param {string | Buffer} content the content
654 * @param {(string | RawSourceMap)=} sourceMap an optional source map
655 * @param {AssociatedObjectForCache=} associatedObjectForCache object for caching
656 * @returns {Source} the created source
657 */
658 createSourceForAsset(
659 context,
660 name,
661 content,
662 sourceMap,
663 associatedObjectForCache
664 ) {
665 if (sourceMap) {
666 if (
667 typeof sourceMap === "string" &&
668 (this.useSourceMap || this.useSimpleSourceMap)
669 ) {
670 return new OriginalSource(
671 content,
672 contextifySourceUrl(context, sourceMap, associatedObjectForCache)
673 );
674 }
675
676 if (this.useSourceMap) {
677 return new SourceMapSource(
678 content,
679 name,
680 contextifySourceMap(
681 context,
682 /** @type {RawSourceMap} */
683 (sourceMap),
684 associatedObjectForCache
685 )
686 );
687 }
688 }
689
690 return new RawSource(content);
691 }
692
693 /**
694 * @private
695 * @template T
696 * @param {ResolverWithOptions} resolver a resolver
697 * @param {WebpackOptions} options webpack options
698 * @param {Compilation} compilation the compilation
699 * @param {InputFileSystem} fs file system from reading
700 * @param {NormalModuleCompilationHooks} hooks the hooks
701 * @returns {import("../declarations/LoaderContext").LoaderContext<T>} loader context
702 */
703 _createLoaderContext(resolver, options, compilation, fs, hooks) {
704 const { requestShortener } = compilation.runtimeTemplate;
705 const getCurrentLoaderName = () => {
706 const currentLoader = this.getCurrentLoader(
707 /** @type {AnyLoaderContext} */
708 (loaderContext)
709 );
710 if (!currentLoader) return "(not in loader scope)";
711 return requestShortener.shorten(currentLoader.loader);
712 };
713 /**
714 * @returns {ResolveContext} resolve context
715 */
716 const getResolveContext = () => ({
717 fileDependencies: {
718 add: (d) =>
719 /** @type {AnyLoaderContext} */
720 (loaderContext).addDependency(d)
721 },
722 contextDependencies: {
723 add: (d) =>
724 /** @type {AnyLoaderContext} */
725 (loaderContext).addContextDependency(d)
726 },
727 missingDependencies: {
728 add: (d) =>
729 /** @type {AnyLoaderContext} */
730 (loaderContext).addMissingDependency(d)
731 }
732 });
733 const getAbsolutify = memoize(() =>
734 absolutify.bindCache(compilation.compiler.root)
735 );
736 const getAbsolutifyInContext = memoize(() =>
737 absolutify.bindContextCache(
738 /** @type {string} */
739 (this.context),
740 compilation.compiler.root
741 )
742 );
743 const getContextify = memoize(() =>
744 contextify.bindCache(compilation.compiler.root)
745 );
746 const getContextifyInContext = memoize(() =>
747 contextify.bindContextCache(
748 /** @type {string} */
749 (this.context),
750 compilation.compiler.root
751 )
752 );
753 const utils = {
754 /**
755 * @param {string} context context
756 * @param {string} request request
757 * @returns {string} result
758 */
759 absolutify: (context, request) =>
760 context === this.context
761 ? getAbsolutifyInContext()(request)
762 : getAbsolutify()(context, request),
763 /**
764 * @param {string} context context
765 * @param {string} request request
766 * @returns {string} result
767 */
768 contextify: (context, request) =>
769 context === this.context
770 ? getContextifyInContext()(request)
771 : getContextify()(context, request),
772 /**
773 * @param {HashFunction=} type type
774 * @returns {Hash} hash
775 */
776 createHash: (type) =>
777 createHash(type || compilation.outputOptions.hashFunction)
778 };
779 /** @type {NormalModuleLoaderContext<T>} */
780 const loaderContext = {
781 version: 2,
782 /**
783 * @param {import("../declarations/LoaderContext").Schema=} schema schema
784 * @returns {T} options
785 */
786 getOptions: (schema) => {
787 const loader = this.getCurrentLoader(
788 /** @type {AnyLoaderContext} */
789 (loaderContext)
790 );
791
792 let { options } = /** @type {LoaderItem} */ (loader);
793
794 if (typeof options === "string") {
795 if (options.startsWith("{") && options.endsWith("}")) {
796 try {
797 options =
798 /** @type {LoaderItem["options"]} */
799 (parseJson(options));
800 } catch (err) {
801 throw new Error(
802 `Cannot parse string options: ${/** @type {Error} */ (err).message}`,
803 { cause: err }
804 );
805 }
806 } else {
807 options = querystring.parse(options, "&", "=", {
808 maxKeys: 0
809 });
810 }
811 }
812
813 if (options === null || options === undefined) {
814 options = {};
815 }
816
817 if (schema && compilation.options.validate) {
818 let name = "Loader";
819 let baseDataPath = "options";
820 /** @type {RegExpExecArray | null} */
821 let match;
822 if (schema.title && (match = /^(.+) (.+)$/.exec(schema.title))) {
823 [, name, baseDataPath] = match;
824 }
825 getValidate()(schema, /** @type {EXPECTED_OBJECT} */ (options), {
826 name,
827 baseDataPath
828 });
829 }
830
831 return /** @type {T} */ (options);
832 },
833 emitWarning: (warning) => {
834 if (!(warning instanceof Error)) {
835 warning = new NonErrorEmittedError(warning);
836 }
837 this.addWarning(
838 new ModuleWarning(warning, {
839 from: getCurrentLoaderName()
840 })
841 );
842 },
843 emitError: (error) => {
844 if (!(error instanceof Error)) {
845 error = new NonErrorEmittedError(error);
846 }
847 this.addError(
848 new ModuleError(error, {
849 from: getCurrentLoaderName()
850 })
851 );
852 },
853 getLogger: (name) => {
854 const currentLoader = this.getCurrentLoader(
855 /** @type {AnyLoaderContext} */
856 (loaderContext)
857 );
858 return compilation.getLogger(() =>
859 [currentLoader && currentLoader.loader, name, this.identifier()]
860 .filter(Boolean)
861 .join("|")
862 );
863 },
864 resolve(context, request, callback) {
865 resolver.resolve({}, context, request, getResolveContext(), callback);
866 },
867 getResolve(options) {
868 const child = options ? resolver.withOptions(options) : resolver;
869 return /** @type {ReturnType<import("../declarations/LoaderContext").NormalModuleLoaderContext<T>["getResolve"]>} */ (
870 (context, request, callback) => {
871 if (callback) {
872 child.resolve(
873 {},
874 context,
875 request,
876 getResolveContext(),
877 callback
878 );
879 } else {
880 return new Promise((resolve, reject) => {
881 child.resolve(
882 {},
883 context,
884 request,
885 getResolveContext(),
886 (err, result) => {
887 if (err) reject(err);
888 else resolve(result);
889 }
890 );
891 });
892 }
893 }
894 );
895 },
896 emitFile: (name, content, sourceMap, assetInfo) => {
897 const buildInfo = /** @type {BuildInfo} */ (this.buildInfo);
898
899 if (!buildInfo.assets) {
900 buildInfo.assets = Object.create(null);
901 buildInfo.assetsInfo = new Map();
902 }
903
904 const assets =
905 /** @type {NonNullable<KnownBuildInfo["assets"]>} */
906 (buildInfo.assets);
907 const assetsInfo =
908 /** @type {NonNullable<KnownBuildInfo["assetsInfo"]>} */
909 (buildInfo.assetsInfo);
910
911 assets[name] = this.createSourceForAsset(
912 options.context,
913 name,
914 content,
915 sourceMap,
916 compilation.compiler.root
917 );
918 assetsInfo.set(name, assetInfo);
919 },
920 addBuildDependency: (dep) => {
921 const buildInfo = /** @type {BuildInfo} */ (this.buildInfo);
922
923 if (buildInfo.buildDependencies === undefined) {
924 buildInfo.buildDependencies = new LazySet();
925 }
926 buildInfo.buildDependencies.add(dep);
927 },
928 utils,
929 rootContext: options.context,
930 webpack: true,
931 sourceMap: Boolean(this.useSourceMap),
932 mode: options.mode || "production",
933 hashFunction: options.output.hashFunction,
934 hashDigest: options.output.hashDigest,
935 hashDigestLength: options.output.hashDigestLength,
936 hashSalt: options.output.hashSalt,
937 _module: this,
938 _compilation: compilation,
939 _compiler: compilation.compiler,
940 fs
941 };
942
943 Object.assign(loaderContext, options.loader);
944
945 hooks.loader.call(
946 /** @type {AnyLoaderContext} */
947 (loaderContext),
948 this
949 );
950
951 return /** @type {AnyLoaderContext} */ (loaderContext);
952 }
953
954 /**
955 * @param {AnyLoaderContext} loaderContext loader context
956 * @param {number} index index
957 * @returns {LoaderItem | null} loader
958 */
959 getCurrentLoader(loaderContext, index = loaderContext.loaderIndex) {
960 if (
961 this.loaders &&
962 this.loaders.length &&
963 index < this.loaders.length &&
964 index >= 0 &&
965 this.loaders[index]
966 ) {
967 return this.loaders[index];
968 }
969 return null;
970 }
971
972 /**
973 * @param {string} context the compilation context
974 * @param {string | Buffer} content the content
975 * @param {(string | RawSourceMap | null)=} sourceMap an optional source map
976 * @param {AssociatedObjectForCache=} associatedObjectForCache object for caching
977 * @returns {Source} the created source
978 */
979 createSource(context, content, sourceMap, associatedObjectForCache) {
980 if (Buffer.isBuffer(content)) {
981 return new RawSource(content);
982 }
983
984 // if there is no identifier return raw source
985 if (!this.identifier) {
986 return new RawSource(content);
987 }
988
989 // from here on we assume we have an identifier
990 const identifier = this.identifier();
991
992 if (this.useSourceMap && sourceMap) {
993 return new SourceMapSource(
994 content,
995 contextifySourceUrl(context, identifier, associatedObjectForCache),
996 contextifySourceMap(context, sourceMap, associatedObjectForCache)
997 );
998 }
999
1000 if (this.useSourceMap || this.useSimpleSourceMap) {
1001 return new OriginalSource(
1002 content,
1003 contextifySourceUrl(context, identifier, associatedObjectForCache)
1004 );
1005 }
1006
1007 return new RawSource(content);
1008 }
1009
1010 /**
1011 * @param {WebpackOptions} options webpack options
1012 * @param {Compilation} compilation the compilation
1013 * @param {ResolverWithOptions} resolver the resolver
1014 * @param {InputFileSystem} fs the file system
1015 * @param {NormalModuleCompilationHooks} hooks the hooks
1016 * @param {BuildCallback} callback callback function
1017 * @returns {void}
1018 */
1019 _doBuild(options, compilation, resolver, fs, hooks, callback) {
1020 const loaderContext = this._createLoaderContext(
1021 resolver,
1022 options,
1023 compilation,
1024 fs,
1025 hooks
1026 );
1027
1028 /**
1029 * @param {Error | null} err err
1030 * @param {(Result | null)=} result_ result
1031 * @returns {void}
1032 */
1033 const processResult = (err, result_) => {
1034 if (err) {
1035 if (!(err instanceof Error)) {
1036 err = new NonErrorEmittedError(err);
1037 }
1038 const currentLoader = this.getCurrentLoader(loaderContext);
1039 const error = new ModuleBuildError(err, {
1040 from:
1041 currentLoader &&
1042 compilation.runtimeTemplate.requestShortener.shorten(
1043 currentLoader.loader
1044 )
1045 });
1046 return callback(error);
1047 }
1048 const result = hooks.processResult.call(
1049 /** @type {Result} */
1050 (result_),
1051 this
1052 );
1053 const source = result[0];
1054 const sourceMap = result.length >= 1 ? result[1] : null;
1055 const extraInfo = result.length >= 2 ? result[2] : null;
1056
1057 if (!Buffer.isBuffer(source) && typeof source !== "string") {
1058 const currentLoader = this.getCurrentLoader(loaderContext, 0);
1059 const err = new Error(
1060 `Final loader (${
1061 currentLoader
1062 ? compilation.runtimeTemplate.requestShortener.shorten(
1063 currentLoader.loader
1064 )
1065 : "unknown"
1066 }) didn't return a Buffer or String`
1067 );
1068 const error = new ModuleBuildError(err);
1069 return callback(error);
1070 }
1071
1072 const isBinaryModule =
1073 this.generatorOptions && this.generatorOptions.binary !== undefined
1074 ? this.generatorOptions.binary
1075 : this.binary;
1076
1077 this._source = this.createSource(
1078 options.context,
1079 isBinaryModule ? asBuffer(source) : asString(source),
1080 sourceMap,
1081 compilation.compiler.root
1082 );
1083 if (this._sourceSizes !== undefined) this._sourceSizes.clear();
1084 /** @type {PreparsedAst | null} */
1085 this._ast =
1086 typeof extraInfo === "object" &&
1087 extraInfo !== null &&
1088 extraInfo.webpackAST !== undefined
1089 ? extraInfo.webpackAST
1090 : null;
1091 return callback();
1092 };
1093
1094 const buildInfo = /** @type {BuildInfo} */ (this.buildInfo);
1095
1096 buildInfo.fileDependencies = new LazySet();
1097 buildInfo.contextDependencies = new LazySet();
1098 buildInfo.missingDependencies = new LazySet();
1099 buildInfo.cacheable = true;
1100
1101 try {
1102 hooks.beforeLoaders.call(
1103 this.loaders,
1104 this,
1105 /** @type {AnyLoaderContext} */
1106 (loaderContext)
1107 );
1108 } catch (err) {
1109 processResult(/** @type {Error} */ (err));
1110 return;
1111 }
1112
1113 if (this.loaders.length > 0) {
1114 /** @type {BuildInfo} */
1115 (this.buildInfo).buildDependencies = new LazySet();
1116 }
1117
1118 runLoaders(
1119 {
1120 resource: this.resource,
1121 loaders: this.loaders,
1122 context: loaderContext,
1123 /**
1124 * @param {AnyLoaderContext} loaderContext the loader context
1125 * @param {string} resourcePath the resource Path
1126 * @param {(err: Error | null, result?: string | Buffer, sourceMap?: Result[1]) => void} callback callback
1127 * @returns {Promise<void>}
1128 */
1129 processResource: async (loaderContext, resourcePath, callback) => {
1130 /** @type {ReadResource} */
1131 const readResource = (resourcePath, getLoaderContext) => {
1132 const scheme = getScheme(resourcePath);
1133 return new Promise((resolve, reject) => {
1134 hooks.readResource
1135 .for(scheme)
1136 .callAsync(getLoaderContext(resourcePath), (err, result) => {
1137 if (err) {
1138 reject(err);
1139 } else {
1140 if (typeof result !== "string" && !result) {
1141 return reject(
1142 new UnhandledSchemeError(
1143 /** @type {string} */
1144 (scheme),
1145 resourcePath
1146 )
1147 );
1148 }
1149 resolve(result);
1150 }
1151 });
1152 });
1153 };
1154 try {
1155 const result = await readResource(
1156 resourcePath,
1157 () => loaderContext
1158 );
1159 if (
1160 this.extractSourceMap &&
1161 (this.useSourceMap || this.useSimpleSourceMap)
1162 ) {
1163 try {
1164 const { source, sourceMap } = await getExtractSourceMap()(
1165 result,
1166 resourcePath,
1167 /** @type {ReadResource} */
1168 (resourcePath) =>
1169 readResource(
1170 resourcePath,
1171 (resourcePath) =>
1172 /** @type {AnyLoaderContext} */
1173 ({
1174 addDependency(dependency) {
1175 loaderContext.addDependency(dependency);
1176 },
1177 fs: loaderContext.fs,
1178 _module: undefined,
1179 resourcePath,
1180 resource: resourcePath
1181 })
1182 ).catch((err) => {
1183 throw new Error(
1184 `Failed to parse source map. ${/** @type {Error} */ (err).message}`
1185 );
1186 })
1187 );
1188 return callback(null, source, sourceMap);
1189 } catch (err) {
1190 this.addWarning(new ModuleWarning(/** @type {Error} */ (err)));
1191 return callback(null, result);
1192 }
1193 }
1194 return callback(null, result);
1195 } catch (error) {
1196 return callback(/** @type {Error} */ (error));
1197 }
1198 }
1199 },
1200 (err, result) => {
1201 // Cleanup loaderContext to avoid leaking memory in ICs
1202 loaderContext._compilation =
1203 loaderContext._compiler =
1204 loaderContext._module =
1205 loaderContext.fs =
1206 /** @type {EXPECTED_ANY} */
1207 (undefined);
1208
1209 if (!result) {
1210 /** @type {BuildInfo} */
1211 (this.buildInfo).cacheable = false;
1212 return processResult(
1213 err || new Error("No result from loader-runner processing"),
1214 null
1215 );
1216 }
1217
1218 const buildInfo = /** @type {BuildInfo} */ (this.buildInfo);
1219
1220 const fileDependencies =
1221 /** @type {NonNullable<KnownBuildInfo["fileDependencies"]>} */
1222 (buildInfo.fileDependencies);
1223 const contextDependencies =
1224 /** @type {NonNullable<KnownBuildInfo["contextDependencies"]>} */
1225 (buildInfo.contextDependencies);
1226 const missingDependencies =
1227 /** @type {NonNullable<KnownBuildInfo["missingDependencies"]>} */
1228 (buildInfo.missingDependencies);
1229
1230 fileDependencies.addAll(result.fileDependencies);
1231 contextDependencies.addAll(result.contextDependencies);
1232 missingDependencies.addAll(result.missingDependencies);
1233 for (const loader of this.loaders) {
1234 const buildDependencies =
1235 /** @type {NonNullable<KnownBuildInfo["buildDependencies"]>} */
1236 (buildInfo.buildDependencies);
1237
1238 buildDependencies.add(loader.loader);
1239 }
1240 buildInfo.cacheable = buildInfo.cacheable && result.cacheable;
1241 processResult(err, result.result);
1242 }
1243 );
1244 }
1245
1246 /**
1247 * @param {Error} error the error
1248 * @returns {void}
1249 */
1250 markModuleAsErrored(error) {
1251 // Restore build meta from successful build to keep importing state
1252 this.buildMeta = { ...this._lastSuccessfulBuildMeta };
1253 this.error = error;
1254 this.addError(error);
1255 }
1256
1257 /**
1258 * @param {Exclude<NoParse, EXPECTED_ANY[]>} rule rule
1259 * @param {string} content content
1260 * @returns {boolean} result
1261 */
1262 applyNoParseRule(rule, content) {
1263 // must start with "rule" if rule is a string
1264 if (typeof rule === "string") {
1265 return content.startsWith(rule);
1266 }
1267
1268 if (typeof rule === "function") {
1269 return rule(content);
1270 }
1271 // we assume rule is a regexp
1272 return rule.test(content);
1273 }
1274
1275 /**
1276 * @param {undefined | NoParse} noParseRule no parse rule
1277 * @param {string} request request
1278 * @returns {boolean} check if module should not be parsed, returns "true" if the module should !not! be parsed, returns "false" if the module !must! be parsed
1279 */
1280 shouldPreventParsing(noParseRule, request) {
1281 // if no noParseRule exists, return false
1282 // the module !must! be parsed.
1283 if (!noParseRule) {
1284 return false;
1285 }
1286
1287 // we only have one rule to check
1288 if (!Array.isArray(noParseRule)) {
1289 // returns "true" if the module is !not! to be parsed
1290 return this.applyNoParseRule(noParseRule, request);
1291 }
1292
1293 for (let i = 0; i < noParseRule.length; i++) {
1294 const rule = noParseRule[i];
1295 // early exit on first truthy match
1296 // this module is !not! to be parsed
1297 if (this.applyNoParseRule(rule, request)) {
1298 return true;
1299 }
1300 }
1301 // no match found, so this module !should! be parsed
1302 return false;
1303 }
1304
1305 /**
1306 * @param {Compilation} compilation compilation
1307 * @private
1308 */
1309 _initBuildHash(compilation) {
1310 const hash = createHash(compilation.outputOptions.hashFunction);
1311 if (this._source) {
1312 hash.update("source");
1313 this._source.updateHash(hash);
1314 }
1315 hash.update("meta");
1316 hash.update(JSON.stringify(this.buildMeta));
1317 /** @type {BuildInfo} */
1318 (this.buildInfo).hash = hash.digest("hex");
1319 }
1320
1321 /**
1322 * Builds the module using the provided compilation context.
1323 * @param {WebpackOptions} options webpack options
1324 * @param {Compilation} compilation the compilation
1325 * @param {ResolverWithOptions} resolver the resolver
1326 * @param {InputFileSystem} fs the file system
1327 * @param {BuildCallback} callback callback function
1328 * @returns {void}
1329 */
1330 build(options, compilation, resolver, fs, callback) {
1331 this._forceBuild = false;
1332 this._source = null;
1333 if (this._sourceSizes !== undefined) this._sourceSizes.clear();
1334 this._sourceTypes = undefined;
1335 this._ast = null;
1336 this.error = null;
1337 this.clearWarningsAndErrors();
1338 this.clearDependenciesAndBlocks();
1339 this.buildMeta = {};
1340 this.buildInfo = {
1341 cacheable: false,
1342 parsed: true,
1343 fileDependencies: undefined,
1344 contextDependencies: undefined,
1345 missingDependencies: undefined,
1346 buildDependencies: undefined,
1347 valueDependencies: undefined,
1348 hash: undefined,
1349 assets: undefined,
1350 assetsInfo: undefined
1351 };
1352
1353 const startTime = compilation.compiler.fsStartTime || Date.now();
1354
1355 const hooks = NormalModule.getCompilationHooks(compilation);
1356
1357 return this._doBuild(options, compilation, resolver, fs, hooks, (err) => {
1358 // if we have an error mark module as failed and exit
1359 if (err) {
1360 this.markModuleAsErrored(err);
1361 this._initBuildHash(compilation);
1362 return callback();
1363 }
1364
1365 /**
1366 * @param {Error} e error
1367 * @returns {void}
1368 */
1369 const handleParseError = (e) => {
1370 const source = /** @type {Source} */ (this._source).source();
1371 const loaders = this.loaders.map((item) =>
1372 contextify(options.context, item.loader, compilation.compiler.root)
1373 );
1374 const error = new ModuleParseError(source, e, loaders, this.type);
1375 this.markModuleAsErrored(error);
1376 this._initBuildHash(compilation);
1377 return callback();
1378 };
1379
1380 const handleParseResult = () => {
1381 this.dependencies.sort(
1382 concatComparators(
1383 compareSelect((a) => a.loc, compareLocations),
1384 keepOriginalOrder(this.dependencies)
1385 )
1386 );
1387 sortWithSourceOrder(this.dependencies, new WeakMap());
1388 this._initBuildHash(compilation);
1389 this._lastSuccessfulBuildMeta =
1390 /** @type {BuildMeta} */
1391 (this.buildMeta);
1392 return handleBuildDone();
1393 };
1394
1395 const handleBuildDone = () => {
1396 try {
1397 hooks.beforeSnapshot.call(this);
1398 } catch (err) {
1399 this.markModuleAsErrored(/** @type {Error} */ (err));
1400 return callback();
1401 }
1402
1403 const snapshotOptions = compilation.options.snapshot.module;
1404 const { cacheable } = /** @type {BuildInfo} */ (this.buildInfo);
1405 if (!cacheable || !snapshotOptions) {
1406 return callback();
1407 }
1408 // add warning for all non-absolute paths in fileDependencies, etc
1409 // This makes it easier to find problems with watching and/or caching
1410 /** @type {undefined | Set<string>} */
1411 let nonAbsoluteDependencies;
1412 /**
1413 * @param {FileSystemDependencies} deps deps
1414 */
1415 const checkDependencies = (deps) => {
1416 for (const dep of deps) {
1417 if (!ABSOLUTE_PATH_REGEX.test(dep)) {
1418 if (nonAbsoluteDependencies === undefined) {
1419 nonAbsoluteDependencies = new Set();
1420 }
1421 nonAbsoluteDependencies.add(dep);
1422 deps.delete(dep);
1423 try {
1424 const depWithoutGlob = dep.replace(/[\\/]?\*.*$/, "");
1425 const absolute = join(
1426 compilation.fileSystemInfo.fs,
1427 /** @type {string} */
1428 (this.context),
1429 depWithoutGlob
1430 );
1431 if (absolute !== dep && ABSOLUTE_PATH_REGEX.test(absolute)) {
1432 (depWithoutGlob !== dep
1433 ? /** @type {NonNullable<KnownBuildInfo["contextDependencies"]>} */
1434 (
1435 /** @type {BuildInfo} */
1436 (this.buildInfo).contextDependencies
1437 )
1438 : deps
1439 ).add(absolute);
1440 }
1441 } catch (_err) {
1442 // ignore
1443 }
1444 }
1445 }
1446 };
1447 const buildInfo = /** @type {BuildInfo} */ (this.buildInfo);
1448 const fileDependencies =
1449 /** @type {NonNullable<KnownBuildInfo["fileDependencies"]>} */
1450 (buildInfo.fileDependencies);
1451 const contextDependencies =
1452 /** @type {NonNullable<KnownBuildInfo["contextDependencies"]>} */
1453 (buildInfo.contextDependencies);
1454 const missingDependencies =
1455 /** @type {NonNullable<KnownBuildInfo["missingDependencies"]>} */
1456 (buildInfo.missingDependencies);
1457 checkDependencies(fileDependencies);
1458 checkDependencies(missingDependencies);
1459 checkDependencies(contextDependencies);
1460 if (nonAbsoluteDependencies !== undefined) {
1461 const InvalidDependenciesModuleWarning =
1462 getInvalidDependenciesModuleWarning();
1463 this.addWarning(
1464 new InvalidDependenciesModuleWarning(this, nonAbsoluteDependencies)
1465 );
1466 }
1467 // convert file/context/missingDependencies into filesystem snapshot
1468 compilation.fileSystemInfo.createSnapshot(
1469 startTime,
1470 fileDependencies,
1471 contextDependencies,
1472 missingDependencies,
1473 snapshotOptions,
1474 (err, snapshot) => {
1475 if (err) {
1476 this.markModuleAsErrored(err);
1477 return;
1478 }
1479 buildInfo.fileDependencies = undefined;
1480 buildInfo.contextDependencies = undefined;
1481 buildInfo.missingDependencies = undefined;
1482 buildInfo.snapshot = snapshot;
1483 return callback();
1484 }
1485 );
1486 };
1487
1488 try {
1489 hooks.beforeParse.call(this);
1490 } catch (err) {
1491 this.markModuleAsErrored(/** @type {Error} */ (err));
1492 this._initBuildHash(compilation);
1493 return callback();
1494 }
1495
1496 // check if this module should !not! be parsed.
1497 // if so, exit here;
1498 const noParseRule = options.module && options.module.noParse;
1499 if (this.shouldPreventParsing(noParseRule, this.request)) {
1500 // We assume that we need module and exports
1501 /** @type {BuildInfo} */
1502 (this.buildInfo).parsed = false;
1503 this._initBuildHash(compilation);
1504 return handleBuildDone();
1505 }
1506
1507 try {
1508 const source = /** @type {Source} */ (this._source).source();
1509 /** @type {Parser} */
1510 (this.parser).parse(this._ast || source, {
1511 source,
1512 current: this,
1513 module: this,
1514 compilation,
1515 options
1516 });
1517 } catch (parseErr) {
1518 handleParseError(/** @type {Error} */ (parseErr));
1519 return;
1520 }
1521 handleParseResult();
1522 });
1523 }
1524
1525 /**
1526 * Returns the reason this module cannot be concatenated, when one exists.
1527 * @param {ConcatenationBailoutReasonContext} context context
1528 * @returns {string | undefined} reason why this module can't be concatenated, undefined when it can be concatenated
1529 */
1530 getConcatenationBailoutReason(context) {
1531 return /** @type {Generator} */ (
1532 this.generator
1533 ).getConcatenationBailoutReason(this, context);
1534 }
1535
1536 /**
1537 * Gets side effects connection state.
1538 * @param {ModuleGraph} moduleGraph the module graph
1539 * @returns {ConnectionState} how this module should be connected to referencing modules when consumed for side-effects only
1540 */
1541 getSideEffectsConnectionState(moduleGraph) {
1542 // Trampoline `walkSideEffects` so the descent doesn't consume the
1543 // call stack (#20986).
1544 const stack = [walkSideEffects(this, moduleGraph)];
1545 /** @type {ConnectionState} */
1546 let r = false;
1547 while (stack.length > 0) {
1548 const step = stack[stack.length - 1].next(r);
1549 if (step.done) {
1550 stack.pop();
1551 r = step.value;
1552 } else {
1553 stack.push(step.value);
1554 }
1555 }
1556 return r;
1557 }
1558
1559 /**
1560 * Returns the source types this module can generate.
1561 * @returns {SourceTypes} types available (do not mutate)
1562 */
1563 getSourceTypes() {
1564 if (this._sourceTypes === undefined) {
1565 this._sourceTypes = /** @type {Generator} */ (this.generator).getTypes(
1566 this
1567 );
1568 }
1569 return this._sourceTypes;
1570 }
1571
1572 /**
1573 * Generates code and runtime requirements for this module.
1574 * @param {CodeGenerationContext} context context for code generation
1575 * @returns {CodeGenerationResult} result
1576 */
1577 codeGeneration({
1578 dependencyTemplates,
1579 runtimeTemplate,
1580 moduleGraph,
1581 chunkGraph,
1582 runtime,
1583 concatenationScope,
1584 codeGenerationResults,
1585 sourceTypes
1586 }) {
1587 /** @type {RuntimeRequirements} */
1588 const runtimeRequirements = new Set();
1589
1590 const { parsed } = /** @type {BuildInfo} */ (this.buildInfo);
1591
1592 if (!parsed) {
1593 runtimeRequirements.add(RuntimeGlobals.module);
1594 runtimeRequirements.add(RuntimeGlobals.exports);
1595 runtimeRequirements.add(RuntimeGlobals.thisAsExports);
1596 }
1597
1598 const getData = () => this._codeGeneratorData;
1599
1600 /** @type {Sources} */
1601 const sources = new Map();
1602 for (const type of sourceTypes || chunkGraph.getModuleSourceTypes(this)) {
1603 // TODO webpack@6 make generateError required
1604 const generator =
1605 /** @type {Generator & { generateError?: GenerateErrorFn }} */
1606 (this.generator);
1607 const source = this.error
1608 ? generator.generateError
1609 ? generator.generateError(this.error, this, {
1610 dependencyTemplates,
1611 runtimeTemplate,
1612 moduleGraph,
1613 chunkGraph,
1614 runtimeRequirements,
1615 runtime,
1616 concatenationScope,
1617 codeGenerationResults,
1618 getData,
1619 type
1620 })
1621 : new RawSource(
1622 `throw new Error(${JSON.stringify(this.error.message)});`
1623 )
1624 : generator.generate(this, {
1625 dependencyTemplates,
1626 runtimeTemplate,
1627 moduleGraph,
1628 chunkGraph,
1629 runtimeRequirements,
1630 runtime,
1631 concatenationScope,
1632 codeGenerationResults,
1633 getData,
1634 type
1635 });
1636
1637 if (source) {
1638 sources.set(type, new CachedSource(source));
1639 }
1640 }
1641
1642 /** @type {CodeGenerationResult} */
1643 const resultEntry = {
1644 sources,
1645 runtimeRequirements,
1646 data: this._codeGeneratorData
1647 };
1648 return resultEntry;
1649 }
1650
1651 /**
1652 * Gets the original source.
1653 * @returns {Source | null} the original source for the module before webpack transformation
1654 */
1655 originalSource() {
1656 return this._source;
1657 }
1658
1659 /**
1660 * Invalidates the cached state associated with this value.
1661 * @returns {void}
1662 */
1663 invalidateBuild() {
1664 this._forceBuild = true;
1665 }
1666
1667 /**
1668 * Checks whether the module needs to be rebuilt for the current build state.
1669 * @param {NeedBuildContext} context context info
1670 * @param {NeedBuildCallback} callback callback function, returns true, if the module needs a rebuild
1671 * @returns {void}
1672 */
1673 needBuild(context, callback) {
1674 const { fileSystemInfo, compilation, valueCacheVersions } = context;
1675 // build if enforced
1676 if (this._forceBuild) return callback(null, true);
1677
1678 // always try to build in case of an error
1679 if (this.error) return callback(null, true);
1680
1681 const { cacheable, snapshot, valueDependencies } =
1682 /** @type {BuildInfo} */ (this.buildInfo);
1683
1684 // always build when module is not cacheable
1685 if (!cacheable) return callback(null, true);
1686
1687 // build when there is no snapshot to check
1688 if (!snapshot) return callback(null, true);
1689
1690 // build when valueDependencies have changed
1691 if (valueDependencies) {
1692 if (!valueCacheVersions) return callback(null, true);
1693 for (const [key, value] of valueDependencies) {
1694 if (value === undefined) return callback(null, true);
1695 const current = valueCacheVersions.get(key);
1696 if (
1697 value !== current &&
1698 (typeof value === "string" ||
1699 typeof current === "string" ||
1700 current === undefined ||
1701 !isSubset(value, current))
1702 ) {
1703 return callback(null, true);
1704 }
1705 }
1706 }
1707
1708 // check snapshot for validity
1709 fileSystemInfo.checkSnapshotValid(snapshot, (err, valid) => {
1710 if (err) return callback(err);
1711 if (!valid) return callback(null, true);
1712 const hooks = NormalModule.getCompilationHooks(compilation);
1713 hooks.needBuild.callAsync(this, context, (err, needBuild) => {
1714 if (err) {
1715 return callback(
1716 HookWebpackError.makeWebpackError(
1717 err,
1718 "NormalModule.getCompilationHooks().needBuild"
1719 )
1720 );
1721 }
1722 callback(null, Boolean(needBuild));
1723 });
1724 });
1725 }
1726
1727 /**
1728 * Returns the estimated size for the requested source type.
1729 * @param {string=} type the source type for which the size should be estimated
1730 * @returns {number} the estimated size of the module (must be non-zero)
1731 */
1732 size(type) {
1733 const cachedSize =
1734 this._sourceSizes === undefined ? undefined : this._sourceSizes.get(type);
1735 if (cachedSize !== undefined) {
1736 return cachedSize;
1737 }
1738 const size = Math.max(
1739 1,
1740 /** @type {Generator} */ (this.generator).getSize(this, type)
1741 );
1742 if (this._sourceSizes === undefined) {
1743 this._sourceSizes = new Map();
1744 }
1745 this._sourceSizes.set(type, size);
1746 return size;
1747 }
1748
1749 /**
1750 * Adds the provided file dependencies to the module.
1751 * @param {FileSystemDependencies} fileDependencies set where file dependencies are added to
1752 * @param {FileSystemDependencies} contextDependencies set where context dependencies are added to
1753 * @param {FileSystemDependencies} missingDependencies set where missing dependencies are added to
1754 * @param {FileSystemDependencies} buildDependencies set where build dependencies are added to
1755 */
1756 addCacheDependencies(
1757 fileDependencies,
1758 contextDependencies,
1759 missingDependencies,
1760 buildDependencies
1761 ) {
1762 const { snapshot, buildDependencies: buildDeps } =
1763 /** @type {BuildInfo} */ (this.buildInfo);
1764 if (snapshot) {
1765 fileDependencies.addAll(snapshot.getFileIterable());
1766 contextDependencies.addAll(snapshot.getContextIterable());
1767 missingDependencies.addAll(snapshot.getMissingIterable());
1768 } else {
1769 const {
1770 fileDependencies: fileDeps,
1771 contextDependencies: contextDeps,
1772 missingDependencies: missingDeps
1773 } = /** @type {BuildInfo} */ (this.buildInfo);
1774 if (fileDeps !== undefined) fileDependencies.addAll(fileDeps);
1775 if (contextDeps !== undefined) contextDependencies.addAll(contextDeps);
1776 if (missingDeps !== undefined) missingDependencies.addAll(missingDeps);
1777 }
1778 if (buildDeps !== undefined) {
1779 buildDependencies.addAll(buildDeps);
1780 }
1781 }
1782
1783 /**
1784 * Updates the hash with the data contributed by this instance.
1785 * @param {Hash} hash the hash used to track dependencies
1786 * @param {UpdateHashContext} context context
1787 * @returns {void}
1788 */
1789 updateHash(hash, context) {
1790 const buildInfo = /** @type {BuildInfo} */ (this.buildInfo);
1791 hash.update(
1792 /** @type {string} */
1793 (buildInfo.hash)
1794 );
1795 // Clear cached source types and re-compute so that changes in incoming
1796 // connections (e.g. asset module newly referenced from JS via lazy
1797 // compilation) are reflected in the hash and trigger code generation
1798 // cache invalidation.
1799 // https://github.com/webpack/webpack/issues/20800
1800 this._sourceTypes = undefined;
1801 for (const type of this.getSourceTypes()) {
1802 hash.update(type);
1803 }
1804 /** @type {Generator} */
1805 (this.generator).updateHash(hash, {
1806 module: this,
1807 ...context
1808 });
1809 super.updateHash(hash, context);
1810 }
1811
1812 /**
1813 * Serializes this instance into the provided serializer context.
1814 * @param {ObjectSerializerContext} context context
1815 */
1816 serialize(context) {
1817 const { write } = context;
1818 // deserialize
1819 write(this._source);
1820 write(this.error);
1821 write(this._lastSuccessfulBuildMeta);
1822 write(this._forceBuild);
1823 write(this._codeGeneratorData);
1824 super.serialize(context);
1825 }
1826
1827 /**
1828 * @param {ObjectDeserializerContext} context context
1829 * @returns {NormalModule} module
1830 */
1831 static deserialize(context) {
1832 const obj = new NormalModule({
1833 // will be deserialized by Module
1834 layer: /** @type {EXPECTED_ANY} */ (null),
1835 type: "",
1836 // will be filled by updateCacheModule
1837 resource: "",
1838 context: "",
1839 request: /** @type {EXPECTED_ANY} */ (null),
1840 userRequest: /** @type {EXPECTED_ANY} */ (null),
1841 rawRequest: /** @type {EXPECTED_ANY} */ (null),
1842 loaders: /** @type {EXPECTED_ANY} */ (null),
1843 matchResource: /** @type {EXPECTED_ANY} */ (null),
1844 parser: /** @type {EXPECTED_ANY} */ (null),
1845 parserOptions: /** @type {EXPECTED_ANY} */ (null),
1846 generator: /** @type {EXPECTED_ANY} */ (null),
1847 generatorOptions: /** @type {EXPECTED_ANY} */ (null),
1848 resolveOptions: /** @type {EXPECTED_ANY} */ (null),
1849 extractSourceMap: /** @type {EXPECTED_ANY} */ (null)
1850 });
1851 obj.deserialize(context);
1852 return obj;
1853 }
1854
1855 /**
1856 * Restores this instance from the provided deserializer context.
1857 * @param {ObjectDeserializerContext} context context
1858 */
1859 deserialize(context) {
1860 const { read } = context;
1861 this._source = read();
1862 this.error = read();
1863 this._lastSuccessfulBuildMeta = read();
1864 this._forceBuild = read();
1865 this._codeGeneratorData = read();
1866 super.deserialize(context);
1867 }
1868}
1869
1870makeSerializable(NormalModule, "webpack/lib/NormalModule");
1871
1872module.exports = NormalModule;
Note: See TracBrowser for help on using the repository browser.