HarmonyExportImportedSpecifierDependency.js 34 KB

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