source: trip-planner-front/node_modules/webpack/lib/optimize/ConcatenatedModule.js

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

initial commit

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