source: imaps-frontend/node_modules/webpack/lib/optimize/ConcatenatedModule.js@ 79a0317

main
Last change on this file since 79a0317 was 79a0317, checked in by stefan toskovski <stefantoska84@…>, 4 days ago

F4 Finalna Verzija

  • Property mode set to 100644
File size: 55.1 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 eslintScope = require("eslint-scope");
9const Referencer = require("eslint-scope/lib/referencer");
10const { SyncBailHook } = require("tapable");
11const {
12 CachedSource,
13 ConcatSource,
14 ReplaceSource
15} = require("webpack-sources");
16const ConcatenationScope = require("../ConcatenationScope");
17const { UsageState } = require("../ExportsInfo");
18const Module = require("../Module");
19const { JS_TYPES } = require("../ModuleSourceTypesConstants");
20const { JAVASCRIPT_MODULE_TYPE_ESM } = require("../ModuleTypeConstants");
21const RuntimeGlobals = require("../RuntimeGlobals");
22const Template = require("../Template");
23const HarmonyImportDependency = require("../dependencies/HarmonyImportDependency");
24const JavascriptParser = require("../javascript/JavascriptParser");
25const { equals } = require("../util/ArrayHelpers");
26const LazySet = require("../util/LazySet");
27const { concatComparators } = require("../util/comparators");
28const {
29 RESERVED_NAMES,
30 findNewName,
31 addScopeSymbols,
32 getAllReferences,
33 getPathInAst,
34 getUsedNamesInScopeInfo
35} = require("../util/concatenate");
36const createHash = require("../util/createHash");
37const { makePathsRelative } = require("../util/identifier");
38const makeSerializable = require("../util/makeSerializable");
39const propertyAccess = require("../util/propertyAccess");
40const { propertyName } = require("../util/propertyName");
41const {
42 filterRuntime,
43 intersectRuntime,
44 mergeRuntimeCondition,
45 mergeRuntimeConditionNonFalse,
46 runtimeConditionToString,
47 subtractRuntimeCondition
48} = require("../util/runtime");
49
50/** @typedef {import("eslint-scope").Reference} Reference */
51/** @typedef {import("eslint-scope").Scope} Scope */
52/** @typedef {import("eslint-scope").Variable} Variable */
53/** @typedef {import("webpack-sources").Source} Source */
54/** @typedef {import("../../declarations/WebpackOptions").WebpackOptionsNormalized} WebpackOptions */
55/** @typedef {import("../ChunkGraph")} ChunkGraph */
56/** @typedef {import("../CodeGenerationResults")} CodeGenerationResults */
57/** @typedef {import("../Compilation")} Compilation */
58/** @typedef {import("../Dependency")} Dependency */
59/** @typedef {import("../Dependency").UpdateHashContext} UpdateHashContext */
60/** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */
61/** @typedef {import("../DependencyTemplates")} DependencyTemplates */
62/** @typedef {import("../ExportsInfo").ExportInfo} ExportInfo */
63/** @typedef {import("../Module").BuildInfo} BuildInfo */
64/** @typedef {import("../Module").BuildMeta} BuildMeta */
65/** @typedef {import("../Module").CodeGenerationContext} CodeGenerationContext */
66/** @typedef {import("../Module").CodeGenerationResult} CodeGenerationResult */
67/** @typedef {import("../Module").LibIdentOptions} LibIdentOptions */
68/** @typedef {import("../Module").ReadOnlyRuntimeRequirements} ReadOnlyRuntimeRequirements */
69/** @typedef {import("../Module").RuntimeRequirements} RuntimeRequirements */
70/** @typedef {import("../Module").SourceTypes} SourceTypes */
71/** @typedef {import("../ModuleGraph")} ModuleGraph */
72/** @typedef {import("../ModuleGraphConnection")} ModuleGraphConnection */
73/** @typedef {import("../ModuleGraphConnection").ConnectionState} ConnectionState */
74/** @typedef {import("../ModuleParseError")} ModuleParseError */
75/** @typedef {import("../RequestShortener")} RequestShortener */
76/** @typedef {import("../ResolverFactory").ResolverWithOptions} ResolverWithOptions */
77/** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */
78/** @typedef {import("../WebpackError")} WebpackError */
79/** @typedef {import("../javascript/JavascriptModulesPlugin").ChunkRenderContext} ChunkRenderContext */
80/** @typedef {import("../javascript/JavascriptParser").Program} Program */
81/** @typedef {import("../javascript/JavascriptParser").Range} Range */
82/** @typedef {import("../serialization/ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
83/** @typedef {import("../util/Hash")} Hash */
84/** @typedef {typeof import("../util/Hash")} HashConstructor */
85/** @typedef {import("../util/concatenate").UsedNames} UsedNames */
86/** @typedef {import("../util/fs").InputFileSystem} InputFileSystem */
87/** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */
88
89/**
90 * @template T
91 * @typedef {import("../InitFragment")<T>} InitFragment
92 */
93
94/**
95 * @template T
96 * @typedef {import("../util/comparators").Comparator<T>} Comparator
97 */
98
99// fix eslint-scope to support class properties correctly
100// cspell:word Referencer
101const ReferencerClass = /** @type {any} */ (Referencer);
102if (!ReferencerClass.prototype.PropertyDefinition) {
103 ReferencerClass.prototype.PropertyDefinition =
104 ReferencerClass.prototype.Property;
105}
106
107/**
108 * @typedef {object} ReexportInfo
109 * @property {Module} module
110 * @property {string[]} export
111 */
112
113/** @typedef {RawBinding | SymbolBinding} Binding */
114
115/**
116 * @typedef {object} RawBinding
117 * @property {ModuleInfo} info
118 * @property {string} rawName
119 * @property {string=} comment
120 * @property {string[]} ids
121 * @property {string[]} exportName
122 */
123
124/**
125 * @typedef {object} SymbolBinding
126 * @property {ConcatenatedModuleInfo} info
127 * @property {string} name
128 * @property {string=} comment
129 * @property {string[]} ids
130 * @property {string[]} exportName
131 */
132
133/** @typedef {ConcatenatedModuleInfo | ExternalModuleInfo } ModuleInfo */
134/** @typedef {ConcatenatedModuleInfo | ExternalModuleInfo | ReferenceToModuleInfo } ModuleInfoOrReference */
135
136/**
137 * @typedef {object} ConcatenatedModuleInfo
138 * @property {"concatenated"} type
139 * @property {Module} module
140 * @property {number} index
141 * @property {Program | undefined} ast
142 * @property {Source | undefined} internalSource
143 * @property {ReplaceSource | undefined} source
144 * @property {InitFragment<ChunkRenderContext>[]=} chunkInitFragments
145 * @property {ReadOnlyRuntimeRequirements | undefined} runtimeRequirements
146 * @property {Scope | undefined} globalScope
147 * @property {Scope | undefined} moduleScope
148 * @property {Map<string, string>} internalNames
149 * @property {Map<string, string> | undefined} exportMap
150 * @property {Map<string, string> | undefined} rawExportMap
151 * @property {string=} namespaceExportSymbol
152 * @property {string | undefined} namespaceObjectName
153 * @property {boolean} interopNamespaceObjectUsed
154 * @property {string | undefined} interopNamespaceObjectName
155 * @property {boolean} interopNamespaceObject2Used
156 * @property {string | undefined} interopNamespaceObject2Name
157 * @property {boolean} interopDefaultAccessUsed
158 * @property {string | undefined} interopDefaultAccessName
159 */
160
161/**
162 * @typedef {object} ExternalModuleInfo
163 * @property {"external"} type
164 * @property {Module} module
165 * @property {RuntimeSpec | boolean} runtimeCondition
166 * @property {number} index
167 * @property {string | undefined} name
168 * @property {boolean} interopNamespaceObjectUsed
169 * @property {string | undefined} interopNamespaceObjectName
170 * @property {boolean} interopNamespaceObject2Used
171 * @property {string | undefined} interopNamespaceObject2Name
172 * @property {boolean} interopDefaultAccessUsed
173 * @property {string | undefined} interopDefaultAccessName
174 */
175
176/**
177 * @typedef {object} ReferenceToModuleInfo
178 * @property {"reference"} type
179 * @property {RuntimeSpec | boolean} runtimeCondition
180 * @property {ModuleInfo} target
181 */
182
183/**
184 * @template T
185 * @param {string} property property
186 * @param {function(T[keyof T], T[keyof T]): 0 | 1 | -1} comparator comparator
187 * @returns {Comparator<T>} comparator
188 */
189
190const createComparator = (property, comparator) => (a, b) =>
191 comparator(
192 a[/** @type {keyof T} */ (property)],
193 b[/** @type {keyof T} */ (property)]
194 );
195
196/**
197 * @param {number} a a
198 * @param {number} b b
199 * @returns {0 | 1 | -1} result
200 */
201const compareNumbers = (a, b) => {
202 if (Number.isNaN(a)) {
203 if (!Number.isNaN(b)) {
204 return 1;
205 }
206 } else {
207 if (Number.isNaN(b)) {
208 return -1;
209 }
210 if (a !== b) {
211 return a < b ? -1 : 1;
212 }
213 }
214 return 0;
215};
216const bySourceOrder = createComparator("sourceOrder", compareNumbers);
217const byRangeStart = createComparator("rangeStart", compareNumbers);
218
219/**
220 * @param {Iterable<string>} iterable iterable object
221 * @returns {string} joined iterable object
222 */
223const joinIterableWithComma = iterable => {
224 // This is more performant than Array.from().join(", ")
225 // as it doesn't create an array
226 let str = "";
227 let first = true;
228 for (const item of iterable) {
229 if (first) {
230 first = false;
231 } else {
232 str += ", ";
233 }
234 str += item;
235 }
236 return str;
237};
238
239/**
240 * @typedef {object} ConcatenationEntry
241 * @property {"concatenated" | "external"} type
242 * @property {Module} module
243 * @property {RuntimeSpec | boolean} runtimeCondition
244 */
245
246/**
247 * @param {ModuleGraph} moduleGraph the module graph
248 * @param {ModuleInfo} info module info
249 * @param {string[]} exportName exportName
250 * @param {Map<Module, ModuleInfo>} moduleToInfoMap moduleToInfoMap
251 * @param {RuntimeSpec} runtime for which runtime
252 * @param {RequestShortener} requestShortener the request shortener
253 * @param {RuntimeTemplate} runtimeTemplate the runtime template
254 * @param {Set<ConcatenatedModuleInfo>} neededNamespaceObjects modules for which a namespace object should be generated
255 * @param {boolean} asCall asCall
256 * @param {boolean | undefined} strictHarmonyModule strictHarmonyModule
257 * @param {boolean | undefined} asiSafe asiSafe
258 * @param {Set<ExportInfo>} alreadyVisited alreadyVisited
259 * @returns {Binding} the final variable
260 */
261const getFinalBinding = (
262 moduleGraph,
263 info,
264 exportName,
265 moduleToInfoMap,
266 runtime,
267 requestShortener,
268 runtimeTemplate,
269 neededNamespaceObjects,
270 asCall,
271 strictHarmonyModule,
272 asiSafe,
273 alreadyVisited = new Set()
274) => {
275 const exportsType = info.module.getExportsType(
276 moduleGraph,
277 strictHarmonyModule
278 );
279 if (exportName.length === 0) {
280 switch (exportsType) {
281 case "default-only":
282 info.interopNamespaceObject2Used = true;
283 return {
284 info,
285 rawName: /** @type {string} */ (info.interopNamespaceObject2Name),
286 ids: exportName,
287 exportName
288 };
289 case "default-with-named":
290 info.interopNamespaceObjectUsed = true;
291 return {
292 info,
293 rawName: /** @type {string} */ (info.interopNamespaceObjectName),
294 ids: exportName,
295 exportName
296 };
297 case "namespace":
298 case "dynamic":
299 break;
300 default:
301 throw new Error(`Unexpected exportsType ${exportsType}`);
302 }
303 } else {
304 switch (exportsType) {
305 case "namespace":
306 break;
307 case "default-with-named":
308 switch (exportName[0]) {
309 case "default":
310 exportName = exportName.slice(1);
311 break;
312 case "__esModule":
313 return {
314 info,
315 rawName: "/* __esModule */true",
316 ids: exportName.slice(1),
317 exportName
318 };
319 }
320 break;
321 case "default-only": {
322 const exportId = exportName[0];
323 if (exportId === "__esModule") {
324 return {
325 info,
326 rawName: "/* __esModule */true",
327 ids: exportName.slice(1),
328 exportName
329 };
330 }
331 exportName = exportName.slice(1);
332 if (exportId !== "default") {
333 return {
334 info,
335 rawName:
336 "/* non-default import from default-exporting module */undefined",
337 ids: exportName,
338 exportName
339 };
340 }
341 break;
342 }
343 case "dynamic":
344 switch (exportName[0]) {
345 case "default": {
346 exportName = exportName.slice(1);
347 info.interopDefaultAccessUsed = true;
348 const defaultExport = asCall
349 ? `${info.interopDefaultAccessName}()`
350 : asiSafe
351 ? `(${info.interopDefaultAccessName}())`
352 : asiSafe === false
353 ? `;(${info.interopDefaultAccessName}())`
354 : `${info.interopDefaultAccessName}.a`;
355 return {
356 info,
357 rawName: defaultExport,
358 ids: exportName,
359 exportName
360 };
361 }
362 case "__esModule":
363 return {
364 info,
365 rawName: "/* __esModule */true",
366 ids: exportName.slice(1),
367 exportName
368 };
369 }
370 break;
371 default:
372 throw new Error(`Unexpected exportsType ${exportsType}`);
373 }
374 }
375 if (exportName.length === 0) {
376 switch (info.type) {
377 case "concatenated":
378 neededNamespaceObjects.add(info);
379 return {
380 info,
381 rawName:
382 /** @type {NonNullable<ConcatenatedModuleInfo["namespaceObjectName"]>} */
383 (info.namespaceObjectName),
384 ids: exportName,
385 exportName
386 };
387 case "external":
388 return {
389 info,
390 rawName:
391 /** @type {NonNullable<ExternalModuleInfo["name"]>} */
392 (info.name),
393 ids: exportName,
394 exportName
395 };
396 }
397 }
398 const exportsInfo = moduleGraph.getExportsInfo(info.module);
399 const exportInfo = exportsInfo.getExportInfo(exportName[0]);
400 if (alreadyVisited.has(exportInfo)) {
401 return {
402 info,
403 rawName: "/* circular reexport */ Object(function x() { x() }())",
404 ids: [],
405 exportName
406 };
407 }
408 alreadyVisited.add(exportInfo);
409 switch (info.type) {
410 case "concatenated": {
411 const exportId = exportName[0];
412 if (exportInfo.provided === false) {
413 // It's not provided, but it could be on the prototype
414 neededNamespaceObjects.add(info);
415 return {
416 info,
417 rawName: /** @type {string} */ (info.namespaceObjectName),
418 ids: exportName,
419 exportName
420 };
421 }
422 const directExport = info.exportMap && info.exportMap.get(exportId);
423 if (directExport) {
424 const usedName = /** @type {string[]} */ (
425 exportsInfo.getUsedName(exportName, runtime)
426 );
427 if (!usedName) {
428 return {
429 info,
430 rawName: "/* unused export */ undefined",
431 ids: exportName.slice(1),
432 exportName
433 };
434 }
435 return {
436 info,
437 name: directExport,
438 ids: usedName.slice(1),
439 exportName
440 };
441 }
442 const rawExport = info.rawExportMap && info.rawExportMap.get(exportId);
443 if (rawExport) {
444 return {
445 info,
446 rawName: rawExport,
447 ids: exportName.slice(1),
448 exportName
449 };
450 }
451 const reexport = exportInfo.findTarget(moduleGraph, module =>
452 moduleToInfoMap.has(module)
453 );
454 if (reexport === false) {
455 throw new Error(
456 `Target module of reexport from '${info.module.readableIdentifier(
457 requestShortener
458 )}' is not part of the concatenation (export '${exportId}')\nModules in the concatenation:\n${Array.from(
459 moduleToInfoMap,
460 ([m, info]) =>
461 ` * ${info.type} ${m.readableIdentifier(requestShortener)}`
462 ).join("\n")}`
463 );
464 }
465 if (reexport) {
466 const refInfo = moduleToInfoMap.get(reexport.module);
467 return getFinalBinding(
468 moduleGraph,
469 /** @type {ModuleInfo} */ (refInfo),
470 reexport.export
471 ? [...reexport.export, ...exportName.slice(1)]
472 : exportName.slice(1),
473 moduleToInfoMap,
474 runtime,
475 requestShortener,
476 runtimeTemplate,
477 neededNamespaceObjects,
478 asCall,
479 /** @type {BuildMeta} */
480 (info.module.buildMeta).strictHarmonyModule,
481 asiSafe,
482 alreadyVisited
483 );
484 }
485 if (info.namespaceExportSymbol) {
486 const usedName = /** @type {string[]} */ (
487 exportsInfo.getUsedName(exportName, runtime)
488 );
489 return {
490 info,
491 rawName: /** @type {string} */ (info.namespaceObjectName),
492 ids: usedName,
493 exportName
494 };
495 }
496 throw new Error(
497 `Cannot get final name for export '${exportName.join(
498 "."
499 )}' of ${info.module.readableIdentifier(requestShortener)}`
500 );
501 }
502
503 case "external": {
504 const used = /** @type {string[]} */ (
505 exportsInfo.getUsedName(exportName, runtime)
506 );
507 if (!used) {
508 return {
509 info,
510 rawName: "/* unused export */ undefined",
511 ids: exportName.slice(1),
512 exportName
513 };
514 }
515 const comment = equals(used, exportName)
516 ? ""
517 : Template.toNormalComment(`${exportName.join(".")}`);
518 return { info, rawName: info.name + comment, ids: used, exportName };
519 }
520 }
521};
522
523/**
524 * @param {ModuleGraph} moduleGraph the module graph
525 * @param {ModuleInfo} info module info
526 * @param {string[]} exportName exportName
527 * @param {Map<Module, ModuleInfo>} moduleToInfoMap moduleToInfoMap
528 * @param {RuntimeSpec} runtime for which runtime
529 * @param {RequestShortener} requestShortener the request shortener
530 * @param {RuntimeTemplate} runtimeTemplate the runtime template
531 * @param {Set<ConcatenatedModuleInfo>} neededNamespaceObjects modules for which a namespace object should be generated
532 * @param {boolean} asCall asCall
533 * @param {boolean | undefined} callContext callContext
534 * @param {boolean | undefined} strictHarmonyModule strictHarmonyModule
535 * @param {boolean | undefined} asiSafe asiSafe
536 * @returns {string} the final name
537 */
538const getFinalName = (
539 moduleGraph,
540 info,
541 exportName,
542 moduleToInfoMap,
543 runtime,
544 requestShortener,
545 runtimeTemplate,
546 neededNamespaceObjects,
547 asCall,
548 callContext,
549 strictHarmonyModule,
550 asiSafe
551) => {
552 const binding = getFinalBinding(
553 moduleGraph,
554 info,
555 exportName,
556 moduleToInfoMap,
557 runtime,
558 requestShortener,
559 runtimeTemplate,
560 neededNamespaceObjects,
561 asCall,
562 strictHarmonyModule,
563 asiSafe
564 );
565 {
566 const { ids, comment } = binding;
567 let reference;
568 let isPropertyAccess;
569 if ("rawName" in binding) {
570 reference = `${binding.rawName}${comment || ""}${propertyAccess(ids)}`;
571 isPropertyAccess = ids.length > 0;
572 } else {
573 const { info, name: exportId } = binding;
574 const name = info.internalNames.get(exportId);
575 if (!name) {
576 throw new Error(
577 `The export "${exportId}" in "${info.module.readableIdentifier(
578 requestShortener
579 )}" has no internal name (existing names: ${
580 Array.from(
581 info.internalNames,
582 ([name, symbol]) => `${name}: ${symbol}`
583 ).join(", ") || "none"
584 })`
585 );
586 }
587 reference = `${name}${comment || ""}${propertyAccess(ids)}`;
588 isPropertyAccess = ids.length > 1;
589 }
590 if (isPropertyAccess && asCall && callContext === false) {
591 return asiSafe
592 ? `(0,${reference})`
593 : asiSafe === false
594 ? `;(0,${reference})`
595 : `/*#__PURE__*/Object(${reference})`;
596 }
597 return reference;
598 }
599};
600
601/**
602 * @typedef {object} ConcatenateModuleHooks
603 * @property {SyncBailHook<[Record<string, string>], boolean | void>} exportsDefinitions
604 */
605
606/** @type {WeakMap<Compilation, ConcatenateModuleHooks>} */
607const compilationHooksMap = new WeakMap();
608
609class ConcatenatedModule extends Module {
610 /**
611 * @param {Module} rootModule the root module of the concatenation
612 * @param {Set<Module>} modules all modules in the concatenation (including the root module)
613 * @param {RuntimeSpec} runtime the runtime
614 * @param {Compilation} compilation the compilation
615 * @param {object=} associatedObjectForCache object for caching
616 * @param {string | HashConstructor=} hashFunction hash function to use
617 * @returns {ConcatenatedModule} the module
618 */
619 static create(
620 rootModule,
621 modules,
622 runtime,
623 compilation,
624 associatedObjectForCache,
625 hashFunction = "md4"
626 ) {
627 const identifier = ConcatenatedModule._createIdentifier(
628 rootModule,
629 modules,
630 associatedObjectForCache,
631 hashFunction
632 );
633 return new ConcatenatedModule({
634 identifier,
635 rootModule,
636 modules,
637 runtime,
638 compilation
639 });
640 }
641
642 /**
643 * @param {Compilation} compilation the compilation
644 * @returns {ConcatenateModuleHooks} the attached hooks
645 */
646 static getCompilationHooks(compilation) {
647 let hooks = compilationHooksMap.get(compilation);
648 if (hooks === undefined) {
649 hooks = {
650 exportsDefinitions: new SyncBailHook(["definitions"])
651 };
652 compilationHooksMap.set(compilation, hooks);
653 }
654 return hooks;
655 }
656
657 /**
658 * @param {object} options options
659 * @param {string} options.identifier the identifier of the module
660 * @param {Module} options.rootModule the root module of the concatenation
661 * @param {RuntimeSpec} options.runtime the selected runtime
662 * @param {Set<Module>} options.modules all concatenated modules
663 * @param {Compilation} options.compilation the compilation
664 */
665 constructor({ identifier, rootModule, modules, runtime, compilation }) {
666 super(JAVASCRIPT_MODULE_TYPE_ESM, null, rootModule && rootModule.layer);
667
668 // Info from Factory
669 /** @type {string} */
670 this._identifier = identifier;
671 /** @type {Module} */
672 this.rootModule = rootModule;
673 /** @type {Set<Module>} */
674 this._modules = modules;
675 this._runtime = runtime;
676 this.factoryMeta = rootModule && rootModule.factoryMeta;
677 /** @type {Compilation | undefined} */
678 this.compilation = compilation;
679 }
680
681 /**
682 * Assuming this module is in the cache. Update the (cached) module with
683 * the fresh module from the factory. Usually updates internal references
684 * and properties.
685 * @param {Module} module fresh module
686 * @returns {void}
687 */
688 updateCacheModule(module) {
689 throw new Error("Must not be called");
690 }
691
692 /**
693 * @returns {SourceTypes} types available (do not mutate)
694 */
695 getSourceTypes() {
696 return JS_TYPES;
697 }
698
699 get modules() {
700 return Array.from(this._modules);
701 }
702
703 /**
704 * @returns {string} a unique identifier of the module
705 */
706 identifier() {
707 return this._identifier;
708 }
709
710 /**
711 * @param {RequestShortener} requestShortener the request shortener
712 * @returns {string} a user readable identifier of the module
713 */
714 readableIdentifier(requestShortener) {
715 return `${this.rootModule.readableIdentifier(
716 requestShortener
717 )} + ${this._modules.size - 1} modules`;
718 }
719
720 /**
721 * @param {LibIdentOptions} options options
722 * @returns {string | null} an identifier for library inclusion
723 */
724 libIdent(options) {
725 return this.rootModule.libIdent(options);
726 }
727
728 /**
729 * @returns {string | null} absolute path which should be used for condition matching (usually the resource path)
730 */
731 nameForCondition() {
732 return this.rootModule.nameForCondition();
733 }
734
735 /**
736 * @param {ModuleGraph} moduleGraph the module graph
737 * @returns {ConnectionState} how this module should be connected to referencing modules when consumed for side-effects only
738 */
739 getSideEffectsConnectionState(moduleGraph) {
740 return this.rootModule.getSideEffectsConnectionState(moduleGraph);
741 }
742
743 /**
744 * @param {WebpackOptions} options webpack options
745 * @param {Compilation} compilation the compilation
746 * @param {ResolverWithOptions} resolver the resolver
747 * @param {InputFileSystem} fs the file system
748 * @param {function(WebpackError=): void} callback callback function
749 * @returns {void}
750 */
751 build(options, compilation, resolver, fs, callback) {
752 const { rootModule } = this;
753 const { moduleArgument, exportsArgument } =
754 /** @type {BuildInfo} */
755 (rootModule.buildInfo);
756 this.buildInfo = {
757 strict: true,
758 cacheable: true,
759 moduleArgument,
760 exportsArgument,
761 fileDependencies: new LazySet(),
762 contextDependencies: new LazySet(),
763 missingDependencies: new LazySet(),
764 topLevelDeclarations: new Set(),
765 assets: undefined
766 };
767 this.buildMeta = rootModule.buildMeta;
768 this.clearDependenciesAndBlocks();
769 this.clearWarningsAndErrors();
770
771 for (const m of this._modules) {
772 // populate cacheable
773 if (!(/** @type {BuildInfo} */ (m.buildInfo).cacheable)) {
774 this.buildInfo.cacheable = false;
775 }
776
777 // populate dependencies
778 for (const d of m.dependencies.filter(
779 dep =>
780 !(dep instanceof HarmonyImportDependency) ||
781 !this._modules.has(
782 /** @type {Module} */ (compilation.moduleGraph.getModule(dep))
783 )
784 )) {
785 this.dependencies.push(d);
786 }
787 // populate blocks
788 for (const d of m.blocks) {
789 this.blocks.push(d);
790 }
791
792 // populate warnings
793 const warnings = m.getWarnings();
794 if (warnings !== undefined) {
795 for (const warning of warnings) {
796 this.addWarning(warning);
797 }
798 }
799
800 // populate errors
801 const errors = m.getErrors();
802 if (errors !== undefined) {
803 for (const error of errors) {
804 this.addError(error);
805 }
806 }
807
808 const { assets, assetsInfo, topLevelDeclarations } =
809 /** @type {BuildInfo} */ (m.buildInfo);
810
811 // populate topLevelDeclarations
812 if (topLevelDeclarations) {
813 const topLevelDeclarations = this.buildInfo.topLevelDeclarations;
814 if (topLevelDeclarations !== undefined) {
815 for (const decl of topLevelDeclarations) {
816 topLevelDeclarations.add(decl);
817 }
818 }
819 } else {
820 this.buildInfo.topLevelDeclarations = undefined;
821 }
822
823 // populate assets
824 if (assets) {
825 if (this.buildInfo.assets === undefined) {
826 this.buildInfo.assets = Object.create(null);
827 }
828 Object.assign(
829 /** @type {NonNullable<BuildInfo["assets"]>} */
830 (
831 /** @type {BuildInfo} */
832 (this.buildInfo).assets
833 ),
834 assets
835 );
836 }
837 if (assetsInfo) {
838 if (this.buildInfo.assetsInfo === undefined) {
839 this.buildInfo.assetsInfo = new Map();
840 }
841 for (const [key, value] of assetsInfo) {
842 this.buildInfo.assetsInfo.set(key, value);
843 }
844 }
845 }
846 callback();
847 }
848
849 /**
850 * @param {string=} type the source type for which the size should be estimated
851 * @returns {number} the estimated size of the module (must be non-zero)
852 */
853 size(type) {
854 // Guess size from embedded modules
855 let size = 0;
856 for (const module of this._modules) {
857 size += module.size(type);
858 }
859 return size;
860 }
861
862 /**
863 * @private
864 * @param {Module} rootModule the root of the concatenation
865 * @param {Set<Module>} modulesSet a set of modules which should be concatenated
866 * @param {RuntimeSpec} runtime for this runtime
867 * @param {ModuleGraph} moduleGraph the module graph
868 * @returns {ConcatenationEntry[]} concatenation list
869 */
870 _createConcatenationList(rootModule, modulesSet, runtime, moduleGraph) {
871 /** @type {ConcatenationEntry[]} */
872 const list = [];
873 /** @type {Map<Module, RuntimeSpec | true>} */
874 const existingEntries = new Map();
875
876 /**
877 * @param {Module} module a module
878 * @returns {Iterable<{ connection: ModuleGraphConnection, runtimeCondition: RuntimeSpec | true }>} imported modules in order
879 */
880 const getConcatenatedImports = module => {
881 const connections = Array.from(
882 moduleGraph.getOutgoingConnections(module)
883 );
884 if (module === rootModule) {
885 for (const c of moduleGraph.getOutgoingConnections(this))
886 connections.push(c);
887 }
888 /**
889 * @type {Array<{ connection: ModuleGraphConnection, sourceOrder: number, rangeStart: number }>}
890 */
891 const references = connections
892 .filter(connection => {
893 if (!(connection.dependency instanceof HarmonyImportDependency))
894 return false;
895 return (
896 connection &&
897 connection.resolvedOriginModule === module &&
898 connection.module &&
899 connection.isTargetActive(runtime)
900 );
901 })
902 .map(connection => {
903 const dep = /** @type {HarmonyImportDependency} */ (
904 connection.dependency
905 );
906 return {
907 connection,
908 sourceOrder: dep.sourceOrder,
909 rangeStart: dep.range && dep.range[0]
910 };
911 });
912 /**
913 * bySourceOrder
914 * @example
915 * import a from "a"; // sourceOrder=1
916 * import b from "b"; // sourceOrder=2
917 *
918 * byRangeStart
919 * @example
920 * import {a, b} from "a"; // sourceOrder=1
921 * a.a(); // first range
922 * b.b(); // second range
923 *
924 * If there is no reexport, we have the same source.
925 * If there is reexport, but module has side effects, this will lead to reexport module only.
926 * If there is side-effects-free reexport, we can get simple deterministic result with range start comparison.
927 */
928 references.sort(concatComparators(bySourceOrder, byRangeStart));
929 /** @type {Map<Module, { connection: ModuleGraphConnection, runtimeCondition: RuntimeSpec | true }>} */
930 const referencesMap = new Map();
931 for (const { connection } of references) {
932 const runtimeCondition = filterRuntime(runtime, r =>
933 connection.isTargetActive(r)
934 );
935 if (runtimeCondition === false) continue;
936 const module = connection.module;
937 const entry = referencesMap.get(module);
938 if (entry === undefined) {
939 referencesMap.set(module, { connection, runtimeCondition });
940 continue;
941 }
942 entry.runtimeCondition = mergeRuntimeConditionNonFalse(
943 entry.runtimeCondition,
944 runtimeCondition,
945 runtime
946 );
947 }
948 return referencesMap.values();
949 };
950
951 /**
952 * @param {ModuleGraphConnection} connection graph connection
953 * @param {RuntimeSpec | true} runtimeCondition runtime condition
954 * @returns {void}
955 */
956 const enterModule = (connection, runtimeCondition) => {
957 const module = connection.module;
958 if (!module) return;
959 const existingEntry = existingEntries.get(module);
960 if (existingEntry === true) {
961 return;
962 }
963 if (modulesSet.has(module)) {
964 existingEntries.set(module, true);
965 if (runtimeCondition !== true) {
966 throw new Error(
967 `Cannot runtime-conditional concatenate a module (${module.identifier()} in ${this.rootModule.identifier()}, ${runtimeConditionToString(
968 runtimeCondition
969 )}). This should not happen.`
970 );
971 }
972 const imports = getConcatenatedImports(module);
973 for (const { connection, runtimeCondition } of imports)
974 enterModule(connection, runtimeCondition);
975 list.push({
976 type: "concatenated",
977 module: connection.module,
978 runtimeCondition
979 });
980 } else {
981 if (existingEntry !== undefined) {
982 const reducedRuntimeCondition = subtractRuntimeCondition(
983 runtimeCondition,
984 existingEntry,
985 runtime
986 );
987 if (reducedRuntimeCondition === false) return;
988 runtimeCondition = reducedRuntimeCondition;
989 existingEntries.set(
990 connection.module,
991 mergeRuntimeConditionNonFalse(
992 existingEntry,
993 runtimeCondition,
994 runtime
995 )
996 );
997 } else {
998 existingEntries.set(connection.module, runtimeCondition);
999 }
1000 if (list.length > 0) {
1001 const lastItem = list[list.length - 1];
1002 if (
1003 lastItem.type === "external" &&
1004 lastItem.module === connection.module
1005 ) {
1006 lastItem.runtimeCondition = mergeRuntimeCondition(
1007 lastItem.runtimeCondition,
1008 runtimeCondition,
1009 runtime
1010 );
1011 return;
1012 }
1013 }
1014 list.push({
1015 type: "external",
1016 get module() {
1017 // We need to use a getter here, because the module in the dependency
1018 // could be replaced by some other process (i. e. also replaced with a
1019 // concatenated module)
1020 return connection.module;
1021 },
1022 runtimeCondition
1023 });
1024 }
1025 };
1026
1027 existingEntries.set(rootModule, true);
1028 const imports = getConcatenatedImports(rootModule);
1029 for (const { connection, runtimeCondition } of imports)
1030 enterModule(connection, runtimeCondition);
1031 list.push({
1032 type: "concatenated",
1033 module: rootModule,
1034 runtimeCondition: true
1035 });
1036
1037 return list;
1038 }
1039
1040 /**
1041 * @param {Module} rootModule the root module of the concatenation
1042 * @param {Set<Module>} modules all modules in the concatenation (including the root module)
1043 * @param {object=} associatedObjectForCache object for caching
1044 * @param {string | HashConstructor=} hashFunction hash function to use
1045 * @returns {string} the identifier
1046 */
1047 static _createIdentifier(
1048 rootModule,
1049 modules,
1050 associatedObjectForCache,
1051 hashFunction = "md4"
1052 ) {
1053 const cachedMakePathsRelative = makePathsRelative.bindContextCache(
1054 /** @type {string} */ (rootModule.context),
1055 associatedObjectForCache
1056 );
1057 const identifiers = [];
1058 for (const module of modules) {
1059 identifiers.push(cachedMakePathsRelative(module.identifier()));
1060 }
1061 identifiers.sort();
1062 const hash = createHash(hashFunction);
1063 hash.update(identifiers.join(" "));
1064 return `${rootModule.identifier()}|${hash.digest("hex")}`;
1065 }
1066
1067 /**
1068 * @param {LazySet<string>} fileDependencies set where file dependencies are added to
1069 * @param {LazySet<string>} contextDependencies set where context dependencies are added to
1070 * @param {LazySet<string>} missingDependencies set where missing dependencies are added to
1071 * @param {LazySet<string>} buildDependencies set where build dependencies are added to
1072 */
1073 addCacheDependencies(
1074 fileDependencies,
1075 contextDependencies,
1076 missingDependencies,
1077 buildDependencies
1078 ) {
1079 for (const module of this._modules) {
1080 module.addCacheDependencies(
1081 fileDependencies,
1082 contextDependencies,
1083 missingDependencies,
1084 buildDependencies
1085 );
1086 }
1087 }
1088
1089 /**
1090 * @param {CodeGenerationContext} context context for code generation
1091 * @returns {CodeGenerationResult} result
1092 */
1093 codeGeneration({
1094 dependencyTemplates,
1095 runtimeTemplate,
1096 moduleGraph,
1097 chunkGraph,
1098 runtime: generationRuntime,
1099 codeGenerationResults
1100 }) {
1101 /** @type {RuntimeRequirements} */
1102 const runtimeRequirements = new Set();
1103 const runtime = intersectRuntime(generationRuntime, this._runtime);
1104
1105 const requestShortener = runtimeTemplate.requestShortener;
1106 // Meta info for each module
1107 const [modulesWithInfo, moduleToInfoMap] = this._getModulesWithInfo(
1108 moduleGraph,
1109 runtime
1110 );
1111
1112 // Set with modules that need a generated namespace object
1113 /** @type {Set<ConcatenatedModuleInfo>} */
1114 const neededNamespaceObjects = new Set();
1115
1116 // Generate source code and analyse scopes
1117 // Prepare a ReplaceSource for the final source
1118 for (const info of moduleToInfoMap.values()) {
1119 this._analyseModule(
1120 moduleToInfoMap,
1121 info,
1122 dependencyTemplates,
1123 runtimeTemplate,
1124 moduleGraph,
1125 chunkGraph,
1126 runtime,
1127 /** @type {CodeGenerationResults} */
1128 (codeGenerationResults)
1129 );
1130 }
1131
1132 // List of all used names to avoid conflicts
1133 const allUsedNames = new Set(RESERVED_NAMES);
1134 // Updated Top level declarations are created by renaming
1135 const topLevelDeclarations = new Set();
1136
1137 // List of additional names in scope for module references
1138 /** @type {Map<string, { usedNames: UsedNames, alreadyCheckedScopes: Set<TODO> }>} */
1139 const usedNamesInScopeInfo = new Map();
1140 /**
1141 * @param {string} module module identifier
1142 * @param {string} id export id
1143 * @returns {{ usedNames: UsedNames, alreadyCheckedScopes: Set<TODO> }} info
1144 */
1145
1146 // Set of already checked scopes
1147 const ignoredScopes = new Set();
1148
1149 // get all global names
1150 for (const info of modulesWithInfo) {
1151 if (info.type === "concatenated") {
1152 // ignore symbols from moduleScope
1153 if (info.moduleScope) {
1154 ignoredScopes.add(info.moduleScope);
1155 }
1156
1157 // The super class expression in class scopes behaves weird
1158 // We get ranges of all super class expressions to make
1159 // renaming to work correctly
1160 const superClassCache = new WeakMap();
1161 /**
1162 * @param {Scope} scope scope
1163 * @returns {TODO} result
1164 */
1165 const getSuperClassExpressions = scope => {
1166 const cacheEntry = superClassCache.get(scope);
1167 if (cacheEntry !== undefined) return cacheEntry;
1168 const superClassExpressions = [];
1169 for (const childScope of scope.childScopes) {
1170 if (childScope.type !== "class") continue;
1171 const block = childScope.block;
1172 if (
1173 (block.type === "ClassDeclaration" ||
1174 block.type === "ClassExpression") &&
1175 block.superClass
1176 ) {
1177 superClassExpressions.push({
1178 range: block.superClass.range,
1179 variables: childScope.variables
1180 });
1181 }
1182 }
1183 superClassCache.set(scope, superClassExpressions);
1184 return superClassExpressions;
1185 };
1186
1187 // add global symbols
1188 if (info.globalScope) {
1189 for (const reference of info.globalScope.through) {
1190 const name = reference.identifier.name;
1191 if (ConcatenationScope.isModuleReference(name)) {
1192 const match = ConcatenationScope.matchModuleReference(name);
1193 if (!match) continue;
1194 const referencedInfo = modulesWithInfo[match.index];
1195 if (referencedInfo.type === "reference")
1196 throw new Error("Module reference can't point to a reference");
1197 const binding = getFinalBinding(
1198 moduleGraph,
1199 referencedInfo,
1200 match.ids,
1201 moduleToInfoMap,
1202 runtime,
1203 requestShortener,
1204 runtimeTemplate,
1205 neededNamespaceObjects,
1206 false,
1207 /** @type {BuildMeta} */
1208 (info.module.buildMeta).strictHarmonyModule,
1209 true
1210 );
1211 if (!binding.ids) continue;
1212 const { usedNames, alreadyCheckedScopes } =
1213 getUsedNamesInScopeInfo(
1214 usedNamesInScopeInfo,
1215 binding.info.module.identifier(),
1216 "name" in binding ? binding.name : ""
1217 );
1218 for (const expr of getSuperClassExpressions(reference.from)) {
1219 if (
1220 expr.range[0] <=
1221 /** @type {Range} */ (reference.identifier.range)[0] &&
1222 expr.range[1] >=
1223 /** @type {Range} */ (reference.identifier.range)[1]
1224 ) {
1225 for (const variable of expr.variables) {
1226 usedNames.add(variable.name);
1227 }
1228 }
1229 }
1230 addScopeSymbols(
1231 reference.from,
1232 usedNames,
1233 alreadyCheckedScopes,
1234 ignoredScopes
1235 );
1236 } else {
1237 allUsedNames.add(name);
1238 }
1239 }
1240 }
1241 }
1242 }
1243
1244 // generate names for symbols
1245 for (const info of moduleToInfoMap.values()) {
1246 const { usedNames: namespaceObjectUsedNames } = getUsedNamesInScopeInfo(
1247 usedNamesInScopeInfo,
1248 info.module.identifier(),
1249 ""
1250 );
1251 switch (info.type) {
1252 case "concatenated": {
1253 const variables = /** @type {Scope} */ (info.moduleScope).variables;
1254 for (const variable of variables) {
1255 const name = variable.name;
1256 const { usedNames, alreadyCheckedScopes } = getUsedNamesInScopeInfo(
1257 usedNamesInScopeInfo,
1258 info.module.identifier(),
1259 name
1260 );
1261 if (allUsedNames.has(name) || usedNames.has(name)) {
1262 const references = getAllReferences(variable);
1263 for (const ref of references) {
1264 addScopeSymbols(
1265 ref.from,
1266 usedNames,
1267 alreadyCheckedScopes,
1268 ignoredScopes
1269 );
1270 }
1271 const newName = findNewName(
1272 name,
1273 allUsedNames,
1274 usedNames,
1275 info.module.readableIdentifier(requestShortener)
1276 );
1277 allUsedNames.add(newName);
1278 info.internalNames.set(name, newName);
1279 topLevelDeclarations.add(newName);
1280 const source = /** @type {ReplaceSource} */ (info.source);
1281 const allIdentifiers = new Set(
1282 references.map(r => r.identifier).concat(variable.identifiers)
1283 );
1284 for (const identifier of allIdentifiers) {
1285 const r = /** @type {Range} */ (identifier.range);
1286 const path = getPathInAst(
1287 /** @type {NonNullable<ConcatenatedModuleInfo["ast"]>} */
1288 (info.ast),
1289 identifier
1290 );
1291 if (path && path.length > 1) {
1292 const maybeProperty =
1293 path[1].type === "AssignmentPattern" &&
1294 path[1].left === path[0]
1295 ? path[2]
1296 : path[1];
1297 if (
1298 maybeProperty.type === "Property" &&
1299 maybeProperty.shorthand
1300 ) {
1301 source.insert(r[1], `: ${newName}`);
1302 continue;
1303 }
1304 }
1305 source.replace(r[0], r[1] - 1, newName);
1306 }
1307 } else {
1308 allUsedNames.add(name);
1309 info.internalNames.set(name, name);
1310 topLevelDeclarations.add(name);
1311 }
1312 }
1313 let namespaceObjectName;
1314 if (info.namespaceExportSymbol) {
1315 namespaceObjectName = info.internalNames.get(
1316 info.namespaceExportSymbol
1317 );
1318 } else {
1319 namespaceObjectName = findNewName(
1320 "namespaceObject",
1321 allUsedNames,
1322 namespaceObjectUsedNames,
1323 info.module.readableIdentifier(requestShortener)
1324 );
1325 allUsedNames.add(namespaceObjectName);
1326 }
1327 info.namespaceObjectName =
1328 /** @type {string} */
1329 (namespaceObjectName);
1330 topLevelDeclarations.add(namespaceObjectName);
1331 break;
1332 }
1333 case "external": {
1334 const externalName = findNewName(
1335 "",
1336 allUsedNames,
1337 namespaceObjectUsedNames,
1338 info.module.readableIdentifier(requestShortener)
1339 );
1340 allUsedNames.add(externalName);
1341 info.name = externalName;
1342 topLevelDeclarations.add(externalName);
1343 break;
1344 }
1345 }
1346 const buildMeta = /** @type {BuildMeta} */ (info.module.buildMeta);
1347 if (buildMeta.exportsType !== "namespace") {
1348 const externalNameInterop = findNewName(
1349 "namespaceObject",
1350 allUsedNames,
1351 namespaceObjectUsedNames,
1352 info.module.readableIdentifier(requestShortener)
1353 );
1354 allUsedNames.add(externalNameInterop);
1355 info.interopNamespaceObjectName = externalNameInterop;
1356 topLevelDeclarations.add(externalNameInterop);
1357 }
1358 if (
1359 buildMeta.exportsType === "default" &&
1360 buildMeta.defaultObject !== "redirect"
1361 ) {
1362 const externalNameInterop = findNewName(
1363 "namespaceObject2",
1364 allUsedNames,
1365 namespaceObjectUsedNames,
1366 info.module.readableIdentifier(requestShortener)
1367 );
1368 allUsedNames.add(externalNameInterop);
1369 info.interopNamespaceObject2Name = externalNameInterop;
1370 topLevelDeclarations.add(externalNameInterop);
1371 }
1372 if (buildMeta.exportsType === "dynamic" || !buildMeta.exportsType) {
1373 const externalNameInterop = findNewName(
1374 "default",
1375 allUsedNames,
1376 namespaceObjectUsedNames,
1377 info.module.readableIdentifier(requestShortener)
1378 );
1379 allUsedNames.add(externalNameInterop);
1380 info.interopDefaultAccessName = externalNameInterop;
1381 topLevelDeclarations.add(externalNameInterop);
1382 }
1383 }
1384
1385 // Find and replace references to modules
1386 for (const info of moduleToInfoMap.values()) {
1387 if (info.type === "concatenated") {
1388 const globalScope = /** @type {Scope} */ (info.globalScope);
1389 for (const reference of globalScope.through) {
1390 const name = reference.identifier.name;
1391 const match = ConcatenationScope.matchModuleReference(name);
1392 if (match) {
1393 const referencedInfo = modulesWithInfo[match.index];
1394 if (referencedInfo.type === "reference")
1395 throw new Error("Module reference can't point to a reference");
1396 const finalName = getFinalName(
1397 moduleGraph,
1398 referencedInfo,
1399 match.ids,
1400 moduleToInfoMap,
1401 runtime,
1402 requestShortener,
1403 runtimeTemplate,
1404 neededNamespaceObjects,
1405 match.call,
1406 !match.directImport,
1407 /** @type {BuildMeta} */
1408 (info.module.buildMeta).strictHarmonyModule,
1409 match.asiSafe
1410 );
1411 const r = /** @type {Range} */ (reference.identifier.range);
1412 const source = /** @type {ReplaceSource} */ (info.source);
1413 // range is extended by 2 chars to cover the appended "._"
1414 source.replace(r[0], r[1] + 1, finalName);
1415 }
1416 }
1417 }
1418 }
1419
1420 // Map with all root exposed used exports
1421 /** @type {Map<string, function(RequestShortener): string>} */
1422 const exportsMap = new Map();
1423
1424 // Set with all root exposed unused exports
1425 /** @type {Set<string>} */
1426 const unusedExports = new Set();
1427
1428 const rootInfo = /** @type {ConcatenatedModuleInfo} */ (
1429 moduleToInfoMap.get(this.rootModule)
1430 );
1431 const strictHarmonyModule =
1432 /** @type {BuildMeta} */
1433 (rootInfo.module.buildMeta).strictHarmonyModule;
1434 const exportsInfo = moduleGraph.getExportsInfo(rootInfo.module);
1435 /** @type {Record<string, string>} */
1436 const exportsFinalName = {};
1437 for (const exportInfo of exportsInfo.orderedExports) {
1438 const name = exportInfo.name;
1439 if (exportInfo.provided === false) continue;
1440 const used = exportInfo.getUsedName(undefined, runtime);
1441 if (!used) {
1442 unusedExports.add(name);
1443 continue;
1444 }
1445 exportsMap.set(used, requestShortener => {
1446 try {
1447 const finalName = getFinalName(
1448 moduleGraph,
1449 rootInfo,
1450 [name],
1451 moduleToInfoMap,
1452 runtime,
1453 requestShortener,
1454 runtimeTemplate,
1455 neededNamespaceObjects,
1456 false,
1457 false,
1458 strictHarmonyModule,
1459 true
1460 );
1461 exportsFinalName[used] = finalName;
1462 return `/* ${
1463 exportInfo.isReexport() ? "reexport" : "binding"
1464 } */ ${finalName}`;
1465 } catch (err) {
1466 /** @type {Error} */
1467 (err).message +=
1468 `\nwhile generating the root export '${name}' (used name: '${used}')`;
1469 throw err;
1470 }
1471 });
1472 }
1473
1474 const result = new ConcatSource();
1475
1476 // add harmony compatibility flag (must be first because of possible circular dependencies)
1477 let shouldAddHarmonyFlag = false;
1478 if (
1479 moduleGraph.getExportsInfo(this).otherExportsInfo.getUsed(runtime) !==
1480 UsageState.Unused
1481 ) {
1482 shouldAddHarmonyFlag = true;
1483 }
1484
1485 // define exports
1486 if (exportsMap.size > 0) {
1487 const { exportsDefinitions } = ConcatenatedModule.getCompilationHooks(
1488 /** @type {Compilation} */ (this.compilation)
1489 );
1490
1491 const definitions = [];
1492 for (const [key, value] of exportsMap) {
1493 definitions.push(
1494 `\n ${propertyName(key)}: ${runtimeTemplate.returningFunction(
1495 value(requestShortener)
1496 )}`
1497 );
1498 }
1499 const shouldSkipRenderDefinitions =
1500 exportsDefinitions.call(exportsFinalName);
1501
1502 if (!shouldSkipRenderDefinitions) {
1503 runtimeRequirements.add(RuntimeGlobals.exports);
1504 runtimeRequirements.add(RuntimeGlobals.definePropertyGetters);
1505
1506 if (shouldAddHarmonyFlag) {
1507 result.add("// ESM COMPAT FLAG\n");
1508 result.add(
1509 runtimeTemplate.defineEsModuleFlagStatement({
1510 exportsArgument: this.exportsArgument,
1511 runtimeRequirements
1512 })
1513 );
1514 }
1515
1516 result.add("\n// EXPORTS\n");
1517 result.add(
1518 `${RuntimeGlobals.definePropertyGetters}(${
1519 this.exportsArgument
1520 }, {${definitions.join(",")}\n});\n`
1521 );
1522 } else {
1523 /** @type {BuildMeta} */
1524 (this.buildMeta).exportsFinalName = exportsFinalName;
1525 }
1526 }
1527
1528 // list unused exports
1529 if (unusedExports.size > 0) {
1530 result.add(
1531 `\n// UNUSED EXPORTS: ${joinIterableWithComma(unusedExports)}\n`
1532 );
1533 }
1534
1535 // generate namespace objects
1536 const namespaceObjectSources = new Map();
1537 for (const info of neededNamespaceObjects) {
1538 if (info.namespaceExportSymbol) continue;
1539 const nsObj = [];
1540 const exportsInfo = moduleGraph.getExportsInfo(info.module);
1541 for (const exportInfo of exportsInfo.orderedExports) {
1542 if (exportInfo.provided === false) continue;
1543 const usedName = exportInfo.getUsedName(undefined, runtime);
1544 if (usedName) {
1545 const finalName = getFinalName(
1546 moduleGraph,
1547 info,
1548 [exportInfo.name],
1549 moduleToInfoMap,
1550 runtime,
1551 requestShortener,
1552 runtimeTemplate,
1553 neededNamespaceObjects,
1554 false,
1555 undefined,
1556 /** @type {BuildMeta} */
1557 (info.module.buildMeta).strictHarmonyModule,
1558 true
1559 );
1560 nsObj.push(
1561 `\n ${propertyName(usedName)}: ${runtimeTemplate.returningFunction(
1562 finalName
1563 )}`
1564 );
1565 }
1566 }
1567 const name = info.namespaceObjectName;
1568 const defineGetters =
1569 nsObj.length > 0
1570 ? `${RuntimeGlobals.definePropertyGetters}(${name}, {${nsObj.join(
1571 ","
1572 )}\n});\n`
1573 : "";
1574 if (nsObj.length > 0)
1575 runtimeRequirements.add(RuntimeGlobals.definePropertyGetters);
1576 namespaceObjectSources.set(
1577 info,
1578 `
1579// NAMESPACE OBJECT: ${info.module.readableIdentifier(requestShortener)}
1580var ${name} = {};
1581${RuntimeGlobals.makeNamespaceObject}(${name});
1582${defineGetters}`
1583 );
1584 runtimeRequirements.add(RuntimeGlobals.makeNamespaceObject);
1585 }
1586
1587 // define required namespace objects (must be before evaluation modules)
1588 for (const info of modulesWithInfo) {
1589 if (info.type === "concatenated") {
1590 const source = namespaceObjectSources.get(info);
1591 if (!source) continue;
1592 result.add(source);
1593 }
1594 }
1595
1596 const chunkInitFragments = [];
1597
1598 // evaluate modules in order
1599 for (const rawInfo of modulesWithInfo) {
1600 let name;
1601 let isConditional = false;
1602 const info = rawInfo.type === "reference" ? rawInfo.target : rawInfo;
1603 switch (info.type) {
1604 case "concatenated": {
1605 result.add(
1606 `\n;// ${info.module.readableIdentifier(requestShortener)}\n`
1607 );
1608 result.add(/** @type {ReplaceSource} */ (info.source));
1609 if (info.chunkInitFragments) {
1610 for (const f of info.chunkInitFragments) chunkInitFragments.push(f);
1611 }
1612 if (info.runtimeRequirements) {
1613 for (const r of info.runtimeRequirements) {
1614 runtimeRequirements.add(r);
1615 }
1616 }
1617 name = info.namespaceObjectName;
1618 break;
1619 }
1620 case "external": {
1621 result.add(
1622 `\n// EXTERNAL MODULE: ${info.module.readableIdentifier(
1623 requestShortener
1624 )}\n`
1625 );
1626 runtimeRequirements.add(RuntimeGlobals.require);
1627 const { runtimeCondition } =
1628 /** @type {ExternalModuleInfo | ReferenceToModuleInfo} */ (rawInfo);
1629 const condition = runtimeTemplate.runtimeConditionExpression({
1630 chunkGraph,
1631 runtimeCondition,
1632 runtime,
1633 runtimeRequirements
1634 });
1635 if (condition !== "true") {
1636 isConditional = true;
1637 result.add(`if (${condition}) {\n`);
1638 }
1639 result.add(
1640 `var ${info.name} = ${RuntimeGlobals.require}(${JSON.stringify(
1641 chunkGraph.getModuleId(info.module)
1642 )});`
1643 );
1644 name = info.name;
1645 break;
1646 }
1647 default:
1648 // @ts-expect-error never is expected here
1649 throw new Error(`Unsupported concatenation entry type ${info.type}`);
1650 }
1651 if (info.interopNamespaceObjectUsed) {
1652 runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
1653 result.add(
1654 `\nvar ${info.interopNamespaceObjectName} = /*#__PURE__*/${RuntimeGlobals.createFakeNamespaceObject}(${name}, 2);`
1655 );
1656 }
1657 if (info.interopNamespaceObject2Used) {
1658 runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
1659 result.add(
1660 `\nvar ${info.interopNamespaceObject2Name} = /*#__PURE__*/${RuntimeGlobals.createFakeNamespaceObject}(${name});`
1661 );
1662 }
1663 if (info.interopDefaultAccessUsed) {
1664 runtimeRequirements.add(RuntimeGlobals.compatGetDefaultExport);
1665 result.add(
1666 `\nvar ${info.interopDefaultAccessName} = /*#__PURE__*/${RuntimeGlobals.compatGetDefaultExport}(${name});`
1667 );
1668 }
1669 if (isConditional) {
1670 result.add("\n}");
1671 }
1672 }
1673
1674 const data = new Map();
1675 if (chunkInitFragments.length > 0)
1676 data.set("chunkInitFragments", chunkInitFragments);
1677 data.set("topLevelDeclarations", topLevelDeclarations);
1678
1679 /** @type {CodeGenerationResult} */
1680 const resultEntry = {
1681 sources: new Map([["javascript", new CachedSource(result)]]),
1682 data,
1683 runtimeRequirements
1684 };
1685
1686 return resultEntry;
1687 }
1688
1689 /**
1690 * @param {Map<Module, ModuleInfo>} modulesMap modulesMap
1691 * @param {ModuleInfo} info info
1692 * @param {DependencyTemplates} dependencyTemplates dependencyTemplates
1693 * @param {RuntimeTemplate} runtimeTemplate runtimeTemplate
1694 * @param {ModuleGraph} moduleGraph moduleGraph
1695 * @param {ChunkGraph} chunkGraph chunkGraph
1696 * @param {RuntimeSpec} runtime runtime
1697 * @param {CodeGenerationResults} codeGenerationResults codeGenerationResults
1698 */
1699 _analyseModule(
1700 modulesMap,
1701 info,
1702 dependencyTemplates,
1703 runtimeTemplate,
1704 moduleGraph,
1705 chunkGraph,
1706 runtime,
1707 codeGenerationResults
1708 ) {
1709 if (info.type === "concatenated") {
1710 const m = info.module;
1711 try {
1712 // Create a concatenation scope to track and capture information
1713 const concatenationScope = new ConcatenationScope(modulesMap, info);
1714
1715 // TODO cache codeGeneration results
1716 const codeGenResult = m.codeGeneration({
1717 dependencyTemplates,
1718 runtimeTemplate,
1719 moduleGraph,
1720 chunkGraph,
1721 runtime,
1722 concatenationScope,
1723 codeGenerationResults,
1724 sourceTypes: JS_TYPES
1725 });
1726 const source = /** @type {Source} */ (
1727 codeGenResult.sources.get("javascript")
1728 );
1729 const data = codeGenResult.data;
1730 const chunkInitFragments = data && data.get("chunkInitFragments");
1731 const code = source.source().toString();
1732 let ast;
1733 try {
1734 ast = JavascriptParser._parse(code, {
1735 sourceType: "module"
1736 });
1737 } catch (_err) {
1738 const err = /** @type {TODO} */ (_err);
1739 if (
1740 err.loc &&
1741 typeof err.loc === "object" &&
1742 typeof err.loc.line === "number"
1743 ) {
1744 const lineNumber = err.loc.line;
1745 const lines = code.split("\n");
1746 err.message += `\n| ${lines
1747 .slice(Math.max(0, lineNumber - 3), lineNumber + 2)
1748 .join("\n| ")}`;
1749 }
1750 throw err;
1751 }
1752 const scopeManager = eslintScope.analyze(ast, {
1753 ecmaVersion: 6,
1754 sourceType: "module",
1755 optimistic: true,
1756 ignoreEval: true,
1757 impliedStrict: true
1758 });
1759 const globalScope = /** @type {Scope} */ (scopeManager.acquire(ast));
1760 const moduleScope = globalScope.childScopes[0];
1761 const resultSource = new ReplaceSource(source);
1762 info.runtimeRequirements =
1763 /** @type {ReadOnlyRuntimeRequirements} */
1764 (codeGenResult.runtimeRequirements);
1765 info.ast = ast;
1766 info.internalSource = source;
1767 info.source = resultSource;
1768 info.chunkInitFragments = chunkInitFragments;
1769 info.globalScope = globalScope;
1770 info.moduleScope = moduleScope;
1771 } catch (err) {
1772 /** @type {Error} */
1773 (err).message +=
1774 `\nwhile analyzing module ${m.identifier()} for concatenation`;
1775 throw err;
1776 }
1777 }
1778 }
1779
1780 /**
1781 * @param {ModuleGraph} moduleGraph the module graph
1782 * @param {RuntimeSpec} runtime the runtime
1783 * @returns {[ModuleInfoOrReference[], Map<Module, ModuleInfo>]} module info items
1784 */
1785 _getModulesWithInfo(moduleGraph, runtime) {
1786 const orderedConcatenationList = this._createConcatenationList(
1787 this.rootModule,
1788 this._modules,
1789 runtime,
1790 moduleGraph
1791 );
1792 /** @type {Map<Module, ModuleInfo>} */
1793 const map = new Map();
1794 const list = orderedConcatenationList.map((info, index) => {
1795 let item = map.get(info.module);
1796 if (item === undefined) {
1797 switch (info.type) {
1798 case "concatenated":
1799 item = {
1800 type: "concatenated",
1801 module: info.module,
1802 index,
1803 ast: undefined,
1804 internalSource: undefined,
1805 runtimeRequirements: undefined,
1806 source: undefined,
1807 globalScope: undefined,
1808 moduleScope: undefined,
1809 internalNames: new Map(),
1810 exportMap: undefined,
1811 rawExportMap: undefined,
1812 namespaceExportSymbol: undefined,
1813 namespaceObjectName: undefined,
1814 interopNamespaceObjectUsed: false,
1815 interopNamespaceObjectName: undefined,
1816 interopNamespaceObject2Used: false,
1817 interopNamespaceObject2Name: undefined,
1818 interopDefaultAccessUsed: false,
1819 interopDefaultAccessName: undefined
1820 };
1821 break;
1822 case "external":
1823 item = {
1824 type: "external",
1825 module: info.module,
1826 runtimeCondition: info.runtimeCondition,
1827 index,
1828 name: undefined,
1829 interopNamespaceObjectUsed: false,
1830 interopNamespaceObjectName: undefined,
1831 interopNamespaceObject2Used: false,
1832 interopNamespaceObject2Name: undefined,
1833 interopDefaultAccessUsed: false,
1834 interopDefaultAccessName: undefined
1835 };
1836 break;
1837 default:
1838 throw new Error(
1839 `Unsupported concatenation entry type ${info.type}`
1840 );
1841 }
1842 map.set(
1843 /** @type {ModuleInfo} */ (item).module,
1844 /** @type {ModuleInfo} */ (item)
1845 );
1846 return /** @type {ModuleInfo} */ (item);
1847 }
1848 /** @type {ReferenceToModuleInfo} */
1849 const ref = {
1850 type: "reference",
1851 runtimeCondition: info.runtimeCondition,
1852 target: item
1853 };
1854 return ref;
1855 });
1856 return [list, map];
1857 }
1858
1859 /**
1860 * @param {Hash} hash the hash used to track dependencies
1861 * @param {UpdateHashContext} context context
1862 * @returns {void}
1863 */
1864 updateHash(hash, context) {
1865 const { chunkGraph, runtime } = context;
1866 for (const info of this._createConcatenationList(
1867 this.rootModule,
1868 this._modules,
1869 intersectRuntime(runtime, this._runtime),
1870 chunkGraph.moduleGraph
1871 )) {
1872 switch (info.type) {
1873 case "concatenated":
1874 info.module.updateHash(hash, context);
1875 break;
1876 case "external":
1877 hash.update(`${chunkGraph.getModuleId(info.module)}`);
1878 // TODO runtimeCondition
1879 break;
1880 }
1881 }
1882 super.updateHash(hash, context);
1883 }
1884
1885 /**
1886 * @param {ObjectDeserializerContext} context context
1887 * @returns {ConcatenatedModule} ConcatenatedModule
1888 */
1889 static deserialize(context) {
1890 const obj = new ConcatenatedModule({
1891 identifier: /** @type {EXPECTED_ANY} */ (undefined),
1892 rootModule: /** @type {EXPECTED_ANY} */ (undefined),
1893 modules: /** @type {EXPECTED_ANY} */ (undefined),
1894 runtime: undefined,
1895 compilation: /** @type {EXPECTED_ANY} */ (undefined)
1896 });
1897 obj.deserialize(context);
1898 return obj;
1899 }
1900}
1901
1902makeSerializable(ConcatenatedModule, "webpack/lib/optimize/ConcatenatedModule");
1903
1904module.exports = ConcatenatedModule;
Note: See TracBrowser for help on using the repository browser.