HarmonyExportImportedSpecifierDependency.js 36 KB

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