HarmonyExportImportedSpecifierDependency.js 35 KB

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