UNPKG

34.9 kBJavaScriptView Raw
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6"use strict";
7
8const Dependency = require("../Dependency");
9const { UsageState } = require("../ExportsInfo");
10const HarmonyLinkingError = require("../HarmonyLinkingError");
11const InitFragment = require("../InitFragment");
12const RuntimeGlobals = require("../RuntimeGlobals");
13const Template = require("../Template");
14const { countIterable } = require("../util/IterableHelpers");
15const { first, combine } = require("../util/SetHelpers");
16const makeSerializable = require("../util/makeSerializable");
17const propertyAccess = require("../util/propertyAccess");
18const { getRuntimeKey, keyToRuntime } = require("../util/runtime");
19const HarmonyExportInitFragment = require("./HarmonyExportInitFragment");
20const HarmonyImportDependency = require("./HarmonyImportDependency");
21const processExportInfo = require("./processExportInfo");
22
23/** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */
24/** @typedef {import("../ChunkGraph")} ChunkGraph */
25/** @typedef {import("../Dependency").ExportsSpec} ExportsSpec */
26/** @typedef {import("../Dependency").ReferencedExport} ReferencedExport */
27/** @typedef {import("../Dependency").TRANSITIVE} TRANSITIVE */
28/** @typedef {import("../Dependency").UpdateHashContext} UpdateHashContext */
29/** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */
30/** @typedef {import("../ExportsInfo")} ExportsInfo */
31/** @typedef {import("../ExportsInfo").ExportInfo} ExportInfo */
32/** @typedef {import("../Module")} Module */
33/** @typedef {import("../ModuleGraph")} ModuleGraph */
34/** @typedef {import("../ModuleGraphConnection")} ModuleGraphConnection */
35/** @typedef {import("../ModuleGraphConnection").ConnectionState} ConnectionState */
36/** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */
37/** @typedef {import("../WebpackError")} WebpackError */
38/** @typedef {import("../util/Hash")} Hash */
39/** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */
40
41/** @typedef {"missing"|"unused"|"empty-star"|"reexport-dynamic-default"|"reexport-named-default"|"reexport-namespace-object"|"reexport-fake-namespace-object"|"reexport-undefined"|"normal-reexport"|"dynamic-reexport"} ExportModeType */
42
43const { ExportPresenceModes } = HarmonyImportDependency;
44
45const idsSymbol = Symbol("HarmonyExportImportedSpecifierDependency.ids");
46
47class NormalReexportItem {
48 /**
49 * @param {string} name export name
50 * @param {string[]} ids reexported ids from other module
51 * @param {ExportInfo} exportInfo export info from other module
52 * @param {boolean} checked true, if it should be checked at runtime if this export exists
53 * @param {boolean} hidden true, if it is hidden behind another active export in the same module
54 */
55 constructor(name, ids, exportInfo, checked, hidden) {
56 this.name = name;
57 this.ids = ids;
58 this.exportInfo = exportInfo;
59 this.checked = checked;
60 this.hidden = hidden;
61 }
62}
63
64class ExportMode {
65 /**
66 * @param {ExportModeType} type type of the mode
67 */
68 constructor(type) {
69 /** @type {ExportModeType} */
70 this.type = type;
71
72 // for "normal-reexport":
73 /** @type {NormalReexportItem[] | null} */
74 this.items = null;
75
76 // for "reexport-named-default" | "reexport-fake-namespace-object" | "reexport-namespace-object"
77 /** @type {string|null} */
78 this.name = null;
79 /** @type {ExportInfo | null} */
80 this.partialNamespaceExportInfo = null;
81
82 // for "dynamic-reexport":
83 /** @type {Set<string> | null} */
84 this.ignored = null;
85
86 // for "dynamic-reexport" | "empty-star":
87 /** @type {Set<string> | null} */
88 this.hidden = null;
89
90 // for "missing":
91 /** @type {string | null} */
92 this.userRequest = null;
93
94 // for "reexport-fake-namespace-object":
95 /** @type {number} */
96 this.fakeType = 0;
97 }
98}
99
100const determineExportAssignments = (
101 moduleGraph,
102 dependencies,
103 additionalDependency
104) => {
105 const names = new Set();
106 const dependencyIndices = [];
107
108 if (additionalDependency) {
109 dependencies = dependencies.concat(additionalDependency);
110 }
111
112 for (const dep of dependencies) {
113 const i = dependencyIndices.length;
114 dependencyIndices[i] = names.size;
115 const otherImportedModule = moduleGraph.getModule(dep);
116 if (otherImportedModule) {
117 const exportsInfo = moduleGraph.getExportsInfo(otherImportedModule);
118 for (const exportInfo of exportsInfo.exports) {
119 if (
120 exportInfo.provided === true &&
121 exportInfo.name !== "default" &&
122 !names.has(exportInfo.name)
123 ) {
124 names.add(exportInfo.name);
125 dependencyIndices[i] = names.size;
126 }
127 }
128 }
129 }
130 dependencyIndices.push(names.size);
131
132 return { names: Array.from(names), dependencyIndices };
133};
134
135const findDependencyForName = (
136 { names, dependencyIndices },
137 name,
138 dependencies
139) => {
140 const dependenciesIt = dependencies[Symbol.iterator]();
141 const dependencyIndicesIt = dependencyIndices[Symbol.iterator]();
142 let dependenciesItResult = dependenciesIt.next();
143 let dependencyIndicesItResult = dependencyIndicesIt.next();
144 if (dependencyIndicesItResult.done) return;
145 for (let i = 0; i < names.length; i++) {
146 while (i >= dependencyIndicesItResult.value) {
147 dependenciesItResult = dependenciesIt.next();
148 dependencyIndicesItResult = dependencyIndicesIt.next();
149 if (dependencyIndicesItResult.done) return;
150 }
151 if (names[i] === name) return dependenciesItResult.value;
152 }
153 return undefined;
154};
155
156/**
157 * @param {ModuleGraph} moduleGraph the module graph
158 * @param {HarmonyExportImportedSpecifierDependency} dep the dependency
159 * @param {string} runtimeKey the runtime key
160 * @returns {ExportMode} the export mode
161 */
162const getMode = (moduleGraph, dep, runtimeKey) => {
163 const importedModule = moduleGraph.getModule(dep);
164
165 if (!importedModule) {
166 const mode = new ExportMode("missing");
167
168 mode.userRequest = dep.userRequest;
169
170 return mode;
171 }
172
173 const name = dep.name;
174 const runtime = keyToRuntime(runtimeKey);
175 const parentModule = moduleGraph.getParentModule(dep);
176 const exportsInfo = moduleGraph.getExportsInfo(parentModule);
177
178 if (
179 name
180 ? exportsInfo.getUsed(name, runtime) === UsageState.Unused
181 : exportsInfo.isUsed(runtime) === false
182 ) {
183 const mode = new ExportMode("unused");
184
185 mode.name = name || "*";
186
187 return mode;
188 }
189
190 const importedExportsType = importedModule.getExportsType(
191 moduleGraph,
192 parentModule.buildMeta.strictHarmonyModule
193 );
194
195 const ids = dep.getIds(moduleGraph);
196
197 // Special handling for reexporting the default export
198 // from non-namespace modules
199 if (name && ids.length > 0 && ids[0] === "default") {
200 switch (importedExportsType) {
201 case "dynamic": {
202 const mode = new ExportMode("reexport-dynamic-default");
203
204 mode.name = name;
205
206 return mode;
207 }
208 case "default-only":
209 case "default-with-named": {
210 const exportInfo = exportsInfo.getReadOnlyExportInfo(name);
211 const mode = new ExportMode("reexport-named-default");
212
213 mode.name = name;
214 mode.partialNamespaceExportInfo = exportInfo;
215
216 return mode;
217 }
218 }
219 }
220
221 // reexporting with a fixed name
222 if (name) {
223 let mode;
224 const exportInfo = exportsInfo.getReadOnlyExportInfo(name);
225
226 if (ids.length > 0) {
227 // export { name as name }
228 switch (importedExportsType) {
229 case "default-only":
230 mode = new ExportMode("reexport-undefined");
231 mode.name = name;
232 break;
233 default:
234 mode = new ExportMode("normal-reexport");
235 mode.items = [
236 new NormalReexportItem(name, ids, exportInfo, false, false)
237 ];
238 break;
239 }
240 } else {
241 // export * as name
242 switch (importedExportsType) {
243 case "default-only":
244 mode = new ExportMode("reexport-fake-namespace-object");
245 mode.name = name;
246 mode.partialNamespaceExportInfo = exportInfo;
247 mode.fakeType = 0;
248 break;
249 case "default-with-named":
250 mode = new ExportMode("reexport-fake-namespace-object");
251 mode.name = name;
252 mode.partialNamespaceExportInfo = exportInfo;
253 mode.fakeType = 2;
254 break;
255 case "dynamic":
256 default:
257 mode = new ExportMode("reexport-namespace-object");
258 mode.name = name;
259 mode.partialNamespaceExportInfo = exportInfo;
260 }
261 }
262
263 return mode;
264 }
265
266 // Star reexporting
267
268 const { ignoredExports, exports, checked, hidden } = dep.getStarReexports(
269 moduleGraph,
270 runtime,
271 exportsInfo,
272 importedModule
273 );
274 if (!exports) {
275 // We have too few info about the modules
276 // Delegate the logic to the runtime code
277
278 const mode = new ExportMode("dynamic-reexport");
279 mode.ignored = ignoredExports;
280 mode.hidden = hidden;
281
282 return mode;
283 }
284
285 if (exports.size === 0) {
286 const mode = new ExportMode("empty-star");
287 mode.hidden = hidden;
288
289 return mode;
290 }
291
292 const mode = new ExportMode("normal-reexport");
293
294 mode.items = Array.from(
295 exports,
296 exportName =>
297 new NormalReexportItem(
298 exportName,
299 [exportName],
300 exportsInfo.getReadOnlyExportInfo(exportName),
301 checked.has(exportName),
302 false
303 )
304 );
305 if (hidden !== undefined) {
306 for (const exportName of hidden) {
307 mode.items.push(
308 new NormalReexportItem(
309 exportName,
310 [exportName],
311 exportsInfo.getReadOnlyExportInfo(exportName),
312 false,
313 true
314 )
315 );
316 }
317 }
318
319 return mode;
320};
321
322class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
323 /**
324 * @param {string} request the request string
325 * @param {number} sourceOrder the order in the original source file
326 * @param {string[]} ids the requested export name of the imported module
327 * @param {string | null} name the export name of for this module
328 * @param {Set<string>} activeExports other named exports in the module
329 * @param {ReadonlyArray<HarmonyExportImportedSpecifierDependency> | Iterable<HarmonyExportImportedSpecifierDependency>} otherStarExports other star exports in the module before this import
330 * @param {number} exportPresenceMode mode of checking export names
331 * @param {HarmonyStarExportsList} allStarExports all star exports in the module
332 * @param {Record<string, any>=} assertions import assertions
333 */
334 constructor(
335 request,
336 sourceOrder,
337 ids,
338 name,
339 activeExports,
340 otherStarExports,
341 exportPresenceMode,
342 allStarExports,
343 assertions
344 ) {
345 super(request, sourceOrder, assertions);
346
347 this.ids = ids;
348 this.name = name;
349 this.activeExports = activeExports;
350 this.otherStarExports = otherStarExports;
351 this.exportPresenceMode = exportPresenceMode;
352 this.allStarExports = allStarExports;
353 }
354
355 /**
356 * @returns {boolean | TRANSITIVE} true, when changes to the referenced module could affect the referencing module; TRANSITIVE, when changes to the referenced module could affect referencing modules of the referencing module
357 */
358 couldAffectReferencingModule() {
359 return Dependency.TRANSITIVE;
360 }
361
362 // TODO webpack 6 remove
363 get id() {
364 throw new Error("id was renamed to ids and type changed to string[]");
365 }
366
367 // TODO webpack 6 remove
368 getId() {
369 throw new Error("id was renamed to ids and type changed to string[]");
370 }
371
372 // TODO webpack 6 remove
373 setId() {
374 throw new Error("id was renamed to ids and type changed to string[]");
375 }
376
377 get type() {
378 return "harmony export imported specifier";
379 }
380
381 /**
382 * @param {ModuleGraph} moduleGraph the module graph
383 * @returns {string[]} the imported id
384 */
385 getIds(moduleGraph) {
386 return moduleGraph.getMeta(this)[idsSymbol] || this.ids;
387 }
388
389 /**
390 * @param {ModuleGraph} moduleGraph the module graph
391 * @param {string[]} ids the imported ids
392 * @returns {void}
393 */
394 setIds(moduleGraph, ids) {
395 moduleGraph.getMeta(this)[idsSymbol] = ids;
396 }
397
398 /**
399 * @param {ModuleGraph} moduleGraph the module graph
400 * @param {RuntimeSpec} runtime the runtime
401 * @returns {ExportMode} the export mode
402 */
403 getMode(moduleGraph, runtime) {
404 return moduleGraph.dependencyCacheProvide(
405 this,
406 getRuntimeKey(runtime),
407 getMode
408 );
409 }
410
411 /**
412 * @param {ModuleGraph} moduleGraph the module graph
413 * @param {RuntimeSpec} runtime the runtime
414 * @param {ExportsInfo} exportsInfo exports info about the current module (optional)
415 * @param {Module} importedModule the imported module (optional)
416 * @returns {{exports?: Set<string>, checked?: Set<string>, ignoredExports: Set<string>, hidden?: Set<string>}} information
417 */
418 getStarReexports(
419 moduleGraph,
420 runtime,
421 exportsInfo = moduleGraph.getExportsInfo(moduleGraph.getParentModule(this)),
422 importedModule = moduleGraph.getModule(this)
423 ) {
424 const importedExportsInfo = moduleGraph.getExportsInfo(importedModule);
425
426 const noExtraExports =
427 importedExportsInfo.otherExportsInfo.provided === false;
428 const noExtraImports =
429 exportsInfo.otherExportsInfo.getUsed(runtime) === UsageState.Unused;
430
431 const ignoredExports = new Set(["default", ...this.activeExports]);
432
433 let hiddenExports = undefined;
434 const otherStarExports =
435 this._discoverActiveExportsFromOtherStarExports(moduleGraph);
436 if (otherStarExports !== undefined) {
437 hiddenExports = new Set();
438 for (let i = 0; i < otherStarExports.namesSlice; i++) {
439 hiddenExports.add(otherStarExports.names[i]);
440 }
441 for (const e of ignoredExports) hiddenExports.delete(e);
442 }
443
444 if (!noExtraExports && !noExtraImports) {
445 return {
446 ignoredExports,
447 hidden: hiddenExports
448 };
449 }
450
451 /** @type {Set<string>} */
452 const exports = new Set();
453 /** @type {Set<string>} */
454 const checked = new Set();
455 /** @type {Set<string>} */
456 const hidden = hiddenExports !== undefined ? new Set() : undefined;
457
458 if (noExtraImports) {
459 for (const exportInfo of exportsInfo.orderedExports) {
460 const name = exportInfo.name;
461 if (ignoredExports.has(name)) continue;
462 if (exportInfo.getUsed(runtime) === UsageState.Unused) continue;
463 const importedExportInfo =
464 importedExportsInfo.getReadOnlyExportInfo(name);
465 if (importedExportInfo.provided === false) continue;
466 if (hiddenExports !== undefined && hiddenExports.has(name)) {
467 hidden.add(name);
468 continue;
469 }
470 exports.add(name);
471 if (importedExportInfo.provided === true) continue;
472 checked.add(name);
473 }
474 } else if (noExtraExports) {
475 for (const importedExportInfo of importedExportsInfo.orderedExports) {
476 const name = importedExportInfo.name;
477 if (ignoredExports.has(name)) continue;
478 if (importedExportInfo.provided === false) continue;
479 const exportInfo = exportsInfo.getReadOnlyExportInfo(name);
480 if (exportInfo.getUsed(runtime) === UsageState.Unused) continue;
481 if (hiddenExports !== undefined && hiddenExports.has(name)) {
482 hidden.add(name);
483 continue;
484 }
485 exports.add(name);
486 if (importedExportInfo.provided === true) continue;
487 checked.add(name);
488 }
489 }
490
491 return { ignoredExports, exports, checked, hidden };
492 }
493
494 /**
495 * @param {ModuleGraph} moduleGraph module graph
496 * @returns {null | false | function(ModuleGraphConnection, RuntimeSpec): ConnectionState} function to determine if the connection is active
497 */
498 getCondition(moduleGraph) {
499 return (connection, runtime) => {
500 const mode = this.getMode(moduleGraph, runtime);
501 return mode.type !== "unused" && mode.type !== "empty-star";
502 };
503 }
504
505 /**
506 * @param {ModuleGraph} moduleGraph the module graph
507 * @returns {ConnectionState} how this dependency connects the module to referencing modules
508 */
509 getModuleEvaluationSideEffectsState(moduleGraph) {
510 return false;
511 }
512
513 /**
514 * Returns list of exports referenced by this dependency
515 * @param {ModuleGraph} moduleGraph module graph
516 * @param {RuntimeSpec} runtime the runtime for which the module is analysed
517 * @returns {(string[] | ReferencedExport)[]} referenced exports
518 */
519 getReferencedExports(moduleGraph, runtime) {
520 const mode = this.getMode(moduleGraph, runtime);
521
522 switch (mode.type) {
523 case "missing":
524 case "unused":
525 case "empty-star":
526 case "reexport-undefined":
527 return Dependency.NO_EXPORTS_REFERENCED;
528
529 case "reexport-dynamic-default":
530 return Dependency.EXPORTS_OBJECT_REFERENCED;
531
532 case "reexport-named-default": {
533 if (!mode.partialNamespaceExportInfo)
534 return Dependency.EXPORTS_OBJECT_REFERENCED;
535 /** @type {string[][]} */
536 const referencedExports = [];
537 processExportInfo(
538 runtime,
539 referencedExports,
540 [],
541 /** @type {ExportInfo} */ (mode.partialNamespaceExportInfo)
542 );
543 return referencedExports;
544 }
545
546 case "reexport-namespace-object":
547 case "reexport-fake-namespace-object": {
548 if (!mode.partialNamespaceExportInfo)
549 return Dependency.EXPORTS_OBJECT_REFERENCED;
550 /** @type {string[][]} */
551 const referencedExports = [];
552 processExportInfo(
553 runtime,
554 referencedExports,
555 [],
556 /** @type {ExportInfo} */ (mode.partialNamespaceExportInfo),
557 mode.type === "reexport-fake-namespace-object"
558 );
559 return referencedExports;
560 }
561
562 case "dynamic-reexport":
563 return Dependency.EXPORTS_OBJECT_REFERENCED;
564
565 case "normal-reexport": {
566 const referencedExports = [];
567 for (const { ids, exportInfo, hidden } of mode.items) {
568 if (hidden) continue;
569 processExportInfo(runtime, referencedExports, ids, exportInfo, false);
570 }
571 return referencedExports;
572 }
573
574 default:
575 throw new Error(`Unknown mode ${mode.type}`);
576 }
577 }
578
579 /**
580 * @param {ModuleGraph} moduleGraph the module graph
581 * @returns {{ names: string[], namesSlice: number, dependencyIndices: number[], dependencyIndex: number } | undefined} exported names and their origin dependency
582 */
583 _discoverActiveExportsFromOtherStarExports(moduleGraph) {
584 if (!this.otherStarExports) return undefined;
585
586 const i =
587 "length" in this.otherStarExports
588 ? this.otherStarExports.length
589 : countIterable(this.otherStarExports);
590 if (i === 0) return undefined;
591
592 if (this.allStarExports) {
593 const { names, dependencyIndices } = moduleGraph.cached(
594 determineExportAssignments,
595 this.allStarExports.dependencies
596 );
597
598 return {
599 names,
600 namesSlice: dependencyIndices[i - 1],
601 dependencyIndices,
602 dependencyIndex: i
603 };
604 }
605
606 const { names, dependencyIndices } = moduleGraph.cached(
607 determineExportAssignments,
608 this.otherStarExports,
609 this
610 );
611
612 return {
613 names,
614 namesSlice: dependencyIndices[i - 1],
615 dependencyIndices,
616 dependencyIndex: i
617 };
618 }
619
620 /**
621 * Returns the exported names
622 * @param {ModuleGraph} moduleGraph module graph
623 * @returns {ExportsSpec | undefined} export names
624 */
625 getExports(moduleGraph) {
626 const mode = this.getMode(moduleGraph, undefined);
627
628 switch (mode.type) {
629 case "missing":
630 return undefined;
631 case "dynamic-reexport": {
632 const from = moduleGraph.getConnection(this);
633 return {
634 exports: true,
635 from,
636 canMangle: false,
637 excludeExports: mode.hidden
638 ? combine(mode.ignored, mode.hidden)
639 : mode.ignored,
640 hideExports: mode.hidden,
641 dependencies: [from.module]
642 };
643 }
644 case "empty-star":
645 return {
646 exports: [],
647 hideExports: mode.hidden,
648 dependencies: [moduleGraph.getModule(this)]
649 };
650 // falls through
651 case "normal-reexport": {
652 const from = moduleGraph.getConnection(this);
653 return {
654 exports: Array.from(mode.items, item => ({
655 name: item.name,
656 from,
657 export: item.ids,
658 hidden: item.hidden
659 })),
660 priority: 1,
661 dependencies: [from.module]
662 };
663 }
664 case "reexport-dynamic-default": {
665 {
666 const from = moduleGraph.getConnection(this);
667 return {
668 exports: [
669 {
670 name: mode.name,
671 from,
672 export: ["default"]
673 }
674 ],
675 priority: 1,
676 dependencies: [from.module]
677 };
678 }
679 }
680 case "reexport-undefined":
681 return {
682 exports: [mode.name],
683 dependencies: [moduleGraph.getModule(this)]
684 };
685 case "reexport-fake-namespace-object": {
686 const from = moduleGraph.getConnection(this);
687 return {
688 exports: [
689 {
690 name: mode.name,
691 from,
692 export: null,
693 exports: [
694 {
695 name: "default",
696 canMangle: false,
697 from,
698 export: null
699 }
700 ]
701 }
702 ],
703 priority: 1,
704 dependencies: [from.module]
705 };
706 }
707 case "reexport-namespace-object": {
708 const from = moduleGraph.getConnection(this);
709 return {
710 exports: [
711 {
712 name: mode.name,
713 from,
714 export: null
715 }
716 ],
717 priority: 1,
718 dependencies: [from.module]
719 };
720 }
721 case "reexport-named-default": {
722 const from = moduleGraph.getConnection(this);
723 return {
724 exports: [
725 {
726 name: mode.name,
727 from,
728 export: ["default"]
729 }
730 ],
731 priority: 1,
732 dependencies: [from.module]
733 };
734 }
735 default:
736 throw new Error(`Unknown mode ${mode.type}`);
737 }
738 }
739
740 /**
741 * @param {ModuleGraph} moduleGraph module graph
742 * @returns {number} effective mode
743 */
744 _getEffectiveExportPresenceLevel(moduleGraph) {
745 if (this.exportPresenceMode !== ExportPresenceModes.AUTO)
746 return this.exportPresenceMode;
747 return moduleGraph.getParentModule(this).buildMeta.strictHarmonyModule
748 ? ExportPresenceModes.ERROR
749 : ExportPresenceModes.WARN;
750 }
751
752 /**
753 * Returns warnings
754 * @param {ModuleGraph} moduleGraph module graph
755 * @returns {WebpackError[]} warnings
756 */
757 getWarnings(moduleGraph) {
758 const exportsPresence = this._getEffectiveExportPresenceLevel(moduleGraph);
759 if (exportsPresence === ExportPresenceModes.WARN) {
760 return this._getErrors(moduleGraph);
761 }
762 return null;
763 }
764
765 /**
766 * Returns errors
767 * @param {ModuleGraph} moduleGraph module graph
768 * @returns {WebpackError[]} errors
769 */
770 getErrors(moduleGraph) {
771 const exportsPresence = this._getEffectiveExportPresenceLevel(moduleGraph);
772 if (exportsPresence === ExportPresenceModes.ERROR) {
773 return this._getErrors(moduleGraph);
774 }
775 return null;
776 }
777
778 /**
779 * @param {ModuleGraph} moduleGraph module graph
780 * @returns {WebpackError[] | undefined} errors
781 */
782 _getErrors(moduleGraph) {
783 const ids = this.getIds(moduleGraph);
784 let errors = this.getLinkingErrors(
785 moduleGraph,
786 ids,
787 `(reexported as '${this.name}')`
788 );
789 if (ids.length === 0 && this.name === null) {
790 const potentialConflicts =
791 this._discoverActiveExportsFromOtherStarExports(moduleGraph);
792 if (potentialConflicts && potentialConflicts.namesSlice > 0) {
793 const ownNames = new Set(
794 potentialConflicts.names.slice(
795 potentialConflicts.namesSlice,
796 potentialConflicts.dependencyIndices[
797 potentialConflicts.dependencyIndex
798 ]
799 )
800 );
801 const importedModule = moduleGraph.getModule(this);
802 if (importedModule) {
803 const exportsInfo = moduleGraph.getExportsInfo(importedModule);
804 const conflicts = new Map();
805 for (const exportInfo of exportsInfo.orderedExports) {
806 if (exportInfo.provided !== true) continue;
807 if (exportInfo.name === "default") continue;
808 if (this.activeExports.has(exportInfo.name)) continue;
809 if (ownNames.has(exportInfo.name)) continue;
810 const conflictingDependency = findDependencyForName(
811 potentialConflicts,
812 exportInfo.name,
813 this.allStarExports
814 ? this.allStarExports.dependencies
815 : [...this.otherStarExports, this]
816 );
817 if (!conflictingDependency) continue;
818 const target = exportInfo.getTerminalBinding(moduleGraph);
819 if (!target) continue;
820 const conflictingModule = moduleGraph.getModule(
821 conflictingDependency
822 );
823 if (conflictingModule === importedModule) continue;
824 const conflictingExportInfo = moduleGraph.getExportInfo(
825 conflictingModule,
826 exportInfo.name
827 );
828 const conflictingTarget =
829 conflictingExportInfo.getTerminalBinding(moduleGraph);
830 if (!conflictingTarget) continue;
831 if (target === conflictingTarget) continue;
832 const list = conflicts.get(conflictingDependency.request);
833 if (list === undefined) {
834 conflicts.set(conflictingDependency.request, [exportInfo.name]);
835 } else {
836 list.push(exportInfo.name);
837 }
838 }
839 for (const [request, exports] of conflicts) {
840 if (!errors) errors = [];
841 errors.push(
842 new HarmonyLinkingError(
843 `The requested module '${
844 this.request
845 }' contains conflicting star exports for the ${
846 exports.length > 1 ? "names" : "name"
847 } ${exports
848 .map(e => `'${e}'`)
849 .join(", ")} with the previous requested module '${request}'`
850 )
851 );
852 }
853 }
854 }
855 }
856 return errors;
857 }
858
859 serialize(context) {
860 const { write, setCircularReference } = context;
861
862 setCircularReference(this);
863 write(this.ids);
864 write(this.name);
865 write(this.activeExports);
866 write(this.otherStarExports);
867 write(this.exportPresenceMode);
868 write(this.allStarExports);
869
870 super.serialize(context);
871 }
872
873 deserialize(context) {
874 const { read, setCircularReference } = context;
875
876 setCircularReference(this);
877 this.ids = read();
878 this.name = read();
879 this.activeExports = read();
880 this.otherStarExports = read();
881 this.exportPresenceMode = read();
882 this.allStarExports = read();
883
884 super.deserialize(context);
885 }
886}
887
888makeSerializable(
889 HarmonyExportImportedSpecifierDependency,
890 "webpack/lib/dependencies/HarmonyExportImportedSpecifierDependency"
891);
892
893module.exports = HarmonyExportImportedSpecifierDependency;
894
895HarmonyExportImportedSpecifierDependency.Template = class HarmonyExportImportedSpecifierDependencyTemplate extends (
896 HarmonyImportDependency.Template
897) {
898 /**
899 * @param {Dependency} dependency the dependency for which the template should be applied
900 * @param {ReplaceSource} source the current replace source which can be modified
901 * @param {DependencyTemplateContext} templateContext the context object
902 * @returns {void}
903 */
904 apply(dependency, source, templateContext) {
905 const { moduleGraph, runtime, concatenationScope } = templateContext;
906
907 const dep = /** @type {HarmonyExportImportedSpecifierDependency} */ (
908 dependency
909 );
910
911 const mode = dep.getMode(moduleGraph, runtime);
912
913 if (concatenationScope) {
914 switch (mode.type) {
915 case "reexport-undefined":
916 concatenationScope.registerRawExport(
917 mode.name,
918 "/* reexport non-default export from non-harmony */ undefined"
919 );
920 }
921 return;
922 }
923
924 if (mode.type !== "unused" && mode.type !== "empty-star") {
925 super.apply(dependency, source, templateContext);
926
927 this._addExportFragments(
928 templateContext.initFragments,
929 dep,
930 mode,
931 templateContext.module,
932 moduleGraph,
933 runtime,
934 templateContext.runtimeTemplate,
935 templateContext.runtimeRequirements
936 );
937 }
938 }
939
940 /**
941 * @param {InitFragment[]} initFragments target array for init fragments
942 * @param {HarmonyExportImportedSpecifierDependency} dep dependency
943 * @param {ExportMode} mode the export mode
944 * @param {Module} module the current module
945 * @param {ModuleGraph} moduleGraph the module graph
946 * @param {RuntimeSpec} runtime the runtime
947 * @param {RuntimeTemplate} runtimeTemplate the runtime template
948 * @param {Set<string>} runtimeRequirements runtime requirements
949 * @returns {void}
950 */
951 _addExportFragments(
952 initFragments,
953 dep,
954 mode,
955 module,
956 moduleGraph,
957 runtime,
958 runtimeTemplate,
959 runtimeRequirements
960 ) {
961 const importedModule = moduleGraph.getModule(dep);
962 const importVar = dep.getImportVar(moduleGraph);
963
964 switch (mode.type) {
965 case "missing":
966 case "empty-star":
967 initFragments.push(
968 new InitFragment(
969 "/* empty/unused harmony star reexport */\n",
970 InitFragment.STAGE_HARMONY_EXPORTS,
971 1
972 )
973 );
974 break;
975
976 case "unused":
977 initFragments.push(
978 new InitFragment(
979 `${Template.toNormalComment(
980 `unused harmony reexport ${mode.name}`
981 )}\n`,
982 InitFragment.STAGE_HARMONY_EXPORTS,
983 1
984 )
985 );
986 break;
987
988 case "reexport-dynamic-default":
989 initFragments.push(
990 this.getReexportFragment(
991 module,
992 "reexport default from dynamic",
993 moduleGraph.getExportsInfo(module).getUsedName(mode.name, runtime),
994 importVar,
995 null,
996 runtimeRequirements
997 )
998 );
999 break;
1000
1001 case "reexport-fake-namespace-object":
1002 initFragments.push(
1003 ...this.getReexportFakeNamespaceObjectFragments(
1004 module,
1005 moduleGraph.getExportsInfo(module).getUsedName(mode.name, runtime),
1006 importVar,
1007 mode.fakeType,
1008 runtimeRequirements
1009 )
1010 );
1011 break;
1012
1013 case "reexport-undefined":
1014 initFragments.push(
1015 this.getReexportFragment(
1016 module,
1017 "reexport non-default export from non-harmony",
1018 moduleGraph.getExportsInfo(module).getUsedName(mode.name, runtime),
1019 "undefined",
1020 "",
1021 runtimeRequirements
1022 )
1023 );
1024 break;
1025
1026 case "reexport-named-default":
1027 initFragments.push(
1028 this.getReexportFragment(
1029 module,
1030 "reexport default export from named module",
1031 moduleGraph.getExportsInfo(module).getUsedName(mode.name, runtime),
1032 importVar,
1033 "",
1034 runtimeRequirements
1035 )
1036 );
1037 break;
1038
1039 case "reexport-namespace-object":
1040 initFragments.push(
1041 this.getReexportFragment(
1042 module,
1043 "reexport module object",
1044 moduleGraph.getExportsInfo(module).getUsedName(mode.name, runtime),
1045 importVar,
1046 "",
1047 runtimeRequirements
1048 )
1049 );
1050 break;
1051
1052 case "normal-reexport":
1053 for (const { name, ids, checked, hidden } of mode.items) {
1054 if (hidden) continue;
1055 if (checked) {
1056 initFragments.push(
1057 new InitFragment(
1058 "/* harmony reexport (checked) */ " +
1059 this.getConditionalReexportStatement(
1060 module,
1061 name,
1062 importVar,
1063 ids,
1064 runtimeRequirements
1065 ),
1066 moduleGraph.isAsync(importedModule)
1067 ? InitFragment.STAGE_ASYNC_HARMONY_IMPORTS
1068 : InitFragment.STAGE_HARMONY_IMPORTS,
1069 dep.sourceOrder
1070 )
1071 );
1072 } else {
1073 initFragments.push(
1074 this.getReexportFragment(
1075 module,
1076 "reexport safe",
1077 moduleGraph.getExportsInfo(module).getUsedName(name, runtime),
1078 importVar,
1079 moduleGraph
1080 .getExportsInfo(importedModule)
1081 .getUsedName(ids, runtime),
1082 runtimeRequirements
1083 )
1084 );
1085 }
1086 }
1087 break;
1088
1089 case "dynamic-reexport": {
1090 const ignored = mode.hidden
1091 ? combine(mode.ignored, mode.hidden)
1092 : mode.ignored;
1093 const modern =
1094 runtimeTemplate.supportsConst() &&
1095 runtimeTemplate.supportsArrowFunction();
1096 let content =
1097 "/* harmony reexport (unknown) */ var __WEBPACK_REEXPORT_OBJECT__ = {};\n" +
1098 `/* harmony reexport (unknown) */ for(${
1099 modern ? "const" : "var"
1100 } __WEBPACK_IMPORT_KEY__ in ${importVar}) `;
1101
1102 // Filter out exports which are defined by other exports
1103 // and filter out default export because it cannot be reexported with *
1104 if (ignored.size > 1) {
1105 content +=
1106 "if(" +
1107 JSON.stringify(Array.from(ignored)) +
1108 ".indexOf(__WEBPACK_IMPORT_KEY__) < 0) ";
1109 } else if (ignored.size === 1) {
1110 content += `if(__WEBPACK_IMPORT_KEY__ !== ${JSON.stringify(
1111 first(ignored)
1112 )}) `;
1113 }
1114
1115 content += `__WEBPACK_REEXPORT_OBJECT__[__WEBPACK_IMPORT_KEY__] = `;
1116 if (modern) {
1117 content += `() => ${importVar}[__WEBPACK_IMPORT_KEY__]`;
1118 } else {
1119 content += `function(key) { return ${importVar}[key]; }.bind(0, __WEBPACK_IMPORT_KEY__)`;
1120 }
1121
1122 runtimeRequirements.add(RuntimeGlobals.exports);
1123 runtimeRequirements.add(RuntimeGlobals.definePropertyGetters);
1124
1125 const exportsName = module.exportsArgument;
1126 initFragments.push(
1127 new InitFragment(
1128 `${content}\n/* harmony reexport (unknown) */ ${RuntimeGlobals.definePropertyGetters}(${exportsName}, __WEBPACK_REEXPORT_OBJECT__);\n`,
1129 moduleGraph.isAsync(importedModule)
1130 ? InitFragment.STAGE_ASYNC_HARMONY_IMPORTS
1131 : InitFragment.STAGE_HARMONY_IMPORTS,
1132 dep.sourceOrder
1133 )
1134 );
1135 break;
1136 }
1137
1138 default:
1139 throw new Error(`Unknown mode ${mode.type}`);
1140 }
1141 }
1142
1143 getReexportFragment(
1144 module,
1145 comment,
1146 key,
1147 name,
1148 valueKey,
1149 runtimeRequirements
1150 ) {
1151 const returnValue = this.getReturnValue(name, valueKey);
1152
1153 runtimeRequirements.add(RuntimeGlobals.exports);
1154 runtimeRequirements.add(RuntimeGlobals.definePropertyGetters);
1155
1156 const map = new Map();
1157 map.set(key, `/* ${comment} */ ${returnValue}`);
1158
1159 return new HarmonyExportInitFragment(module.exportsArgument, map);
1160 }
1161
1162 getReexportFakeNamespaceObjectFragments(
1163 module,
1164 key,
1165 name,
1166 fakeType,
1167 runtimeRequirements
1168 ) {
1169 runtimeRequirements.add(RuntimeGlobals.exports);
1170 runtimeRequirements.add(RuntimeGlobals.definePropertyGetters);
1171 runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
1172
1173 const map = new Map();
1174 map.set(
1175 key,
1176 `/* reexport fake namespace object from non-harmony */ ${name}_namespace_cache || (${name}_namespace_cache = ${
1177 RuntimeGlobals.createFakeNamespaceObject
1178 }(${name}${fakeType ? `, ${fakeType}` : ""}))`
1179 );
1180
1181 return [
1182 new InitFragment(
1183 `var ${name}_namespace_cache;\n`,
1184 InitFragment.STAGE_CONSTANTS,
1185 -1,
1186 `${name}_namespace_cache`
1187 ),
1188 new HarmonyExportInitFragment(module.exportsArgument, map)
1189 ];
1190 }
1191
1192 getConditionalReexportStatement(
1193 module,
1194 key,
1195 name,
1196 valueKey,
1197 runtimeRequirements
1198 ) {
1199 if (valueKey === false) {
1200 return "/* unused export */\n";
1201 }
1202
1203 const exportsName = module.exportsArgument;
1204 const returnValue = this.getReturnValue(name, valueKey);
1205
1206 runtimeRequirements.add(RuntimeGlobals.exports);
1207 runtimeRequirements.add(RuntimeGlobals.definePropertyGetters);
1208 runtimeRequirements.add(RuntimeGlobals.hasOwnProperty);
1209
1210 return `if(${RuntimeGlobals.hasOwnProperty}(${name}, ${JSON.stringify(
1211 valueKey[0]
1212 )})) ${
1213 RuntimeGlobals.definePropertyGetters
1214 }(${exportsName}, { ${JSON.stringify(
1215 key
1216 )}: function() { return ${returnValue}; } });\n`;
1217 }
1218
1219 getReturnValue(name, valueKey) {
1220 if (valueKey === null) {
1221 return `${name}_default.a`;
1222 }
1223
1224 if (valueKey === "") {
1225 return name;
1226 }
1227
1228 if (valueKey === false) {
1229 return "/* unused export */ undefined";
1230 }
1231
1232 return `${name}${propertyAccess(valueKey)}`;
1233 }
1234};
1235
1236class HarmonyStarExportsList {
1237 constructor() {
1238 /** @type {HarmonyExportImportedSpecifierDependency[]} */
1239 this.dependencies = [];
1240 }
1241
1242 /**
1243 * @param {HarmonyExportImportedSpecifierDependency} dep dependency
1244 * @returns {void}
1245 */
1246 push(dep) {
1247 this.dependencies.push(dep);
1248 }
1249
1250 slice() {
1251 return this.dependencies.slice();
1252 }
1253
1254 serialize({ write, setCircularReference }) {
1255 setCircularReference(this);
1256 write(this.dependencies);
1257 }
1258
1259 deserialize({ read, setCircularReference }) {
1260 setCircularReference(this);
1261 this.dependencies = read();
1262 }
1263}
1264
1265makeSerializable(
1266 HarmonyStarExportsList,
1267 "webpack/lib/dependencies/HarmonyExportImportedSpecifierDependency",
1268 "HarmonyStarExportsList"
1269);
1270
1271module.exports.HarmonyStarExportsList = HarmonyStarExportsList;