HarmonyExportImportedSpecifierDependency.js (34884B)
1 /* 2 MIT License http://www.opensource.org/licenses/mit-license.php 3 Author Tobias Koppers @sokra 4 */ 5 6 "use strict"; 7 8 const Dependency = require("../Dependency"); 9 const { UsageState } = require("../ExportsInfo"); 10 const HarmonyLinkingError = require("../HarmonyLinkingError"); 11 const InitFragment = require("../InitFragment"); 12 const RuntimeGlobals = require("../RuntimeGlobals"); 13 const Template = require("../Template"); 14 const { countIterable } = require("../util/IterableHelpers"); 15 const { first, combine } = require("../util/SetHelpers"); 16 const makeSerializable = require("../util/makeSerializable"); 17 const propertyAccess = require("../util/propertyAccess"); 18 const { getRuntimeKey, keyToRuntime } = require("../util/runtime"); 19 const HarmonyExportInitFragment = require("./HarmonyExportInitFragment"); 20 const HarmonyImportDependency = require("./HarmonyImportDependency"); 21 const 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 43 const { ExportPresenceModes } = HarmonyImportDependency; 44 45 const idsSymbol = Symbol("HarmonyExportImportedSpecifierDependency.ids"); 46 47 class 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 64 class 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 100 const 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 135 const 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 */ 162 const 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 322 class 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 888 makeSerializable( 889 HarmonyExportImportedSpecifierDependency, 890 "webpack/lib/dependencies/HarmonyExportImportedSpecifierDependency" 891 ); 892 893 module.exports = HarmonyExportImportedSpecifierDependency; 894 895 HarmonyExportImportedSpecifierDependency.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 1236 class 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 1265 makeSerializable( 1266 HarmonyStarExportsList, 1267 "webpack/lib/dependencies/HarmonyExportImportedSpecifierDependency", 1268 "HarmonyStarExportsList" 1269 ); 1270 1271 module.exports.HarmonyStarExportsList = HarmonyStarExportsList;