ModuleGraph.js 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const util = require("util");
  7. const ExportsInfo = require("./ExportsInfo");
  8. const ModuleGraphConnection = require("./ModuleGraphConnection");
  9. const HarmonyImportDependency = require("./dependencies/HarmonyImportDependency");
  10. const { ImportPhaseUtils } = require("./dependencies/ImportPhase");
  11. const SortableSet = require("./util/SortableSet");
  12. const WeakTupleMap = require("./util/WeakTupleMap");
  13. const { sortWithSourceOrder } = require("./util/comparators");
  14. /** @typedef {import("./Compilation").ModuleMemCaches} ModuleMemCaches */
  15. /** @typedef {import("./DependenciesBlock")} DependenciesBlock */
  16. /** @typedef {import("./Dependency")} Dependency */
  17. /** @typedef {import("./ExportsInfo").ExportInfo} ExportInfo */
  18. /** @typedef {import("./ExportsInfo").ExportInfoName} ExportInfoName */
  19. /** @typedef {import("./Module")} Module */
  20. /** @typedef {import("./ModuleProfile")} ModuleProfile */
  21. /** @typedef {import("./RequestShortener")} RequestShortener */
  22. /** @typedef {import("./util/runtime").RuntimeSpec} RuntimeSpec */
  23. /** @typedef {import("./dependencies/HarmonyImportSideEffectDependency")} HarmonyImportSideEffectDependency */
  24. /** @typedef {import("./dependencies/HarmonyImportSpecifierDependency")} HarmonyImportSpecifierDependency */
  25. /** @typedef {import("./util/comparators").DependencySourceOrder} DependencySourceOrder */
  26. /**
  27. * @callback OptimizationBailoutFunction
  28. * @param {RequestShortener} requestShortener
  29. * @returns {string}
  30. */
  31. /** @type {Iterable<ModuleGraphConnection>} */
  32. const EMPTY_SET = new Set();
  33. /**
  34. * @template {Module | null | undefined} T
  35. * @param {SortableSet<ModuleGraphConnection>} set input
  36. * @param {(connection: ModuleGraphConnection) => T} getKey function to extract key from connection
  37. * @returns {ReadonlyMap<T, ReadonlyArray<ModuleGraphConnection>>} mapped by key
  38. */
  39. const getConnectionsByKey = (set, getKey) => {
  40. /** @type {Map<T, ModuleGraphConnection[]>} */
  41. const map = new Map();
  42. /** @type {T | 0} */
  43. let lastKey = 0;
  44. /** @type {ModuleGraphConnection[] | undefined} */
  45. let lastList;
  46. for (const connection of set) {
  47. const key = getKey(connection);
  48. if (lastKey === key) {
  49. /** @type {ModuleGraphConnection[]} */
  50. (lastList).push(connection);
  51. } else {
  52. lastKey = key;
  53. const list = map.get(key);
  54. if (list !== undefined) {
  55. lastList = list;
  56. list.push(connection);
  57. } else {
  58. const list = [connection];
  59. lastList = list;
  60. map.set(key, list);
  61. }
  62. }
  63. }
  64. return map;
  65. };
  66. /**
  67. * @param {SortableSet<ModuleGraphConnection>} set input
  68. * @returns {ReadonlyMap<Module | undefined | null, ReadonlyArray<ModuleGraphConnection>>} mapped by origin module
  69. */
  70. const getConnectionsByOriginModule = (set) =>
  71. getConnectionsByKey(set, (connection) => connection.originModule);
  72. /**
  73. * @param {SortableSet<ModuleGraphConnection>} set input
  74. * @returns {ReadonlyMap<Module | undefined, ReadonlyArray<ModuleGraphConnection>>} mapped by module
  75. */
  76. const getConnectionsByModule = (set) =>
  77. getConnectionsByKey(set, (connection) => connection.module);
  78. /** @typedef {SortableSet<ModuleGraphConnection>} IncomingConnections */
  79. /** @typedef {SortableSet<ModuleGraphConnection>} OutgoingConnections */
  80. /** @typedef {Module | null | undefined} Issuer */
  81. /** @typedef {(string | OptimizationBailoutFunction)[]} OptimizationBailouts */
  82. class ModuleGraphModule {
  83. constructor() {
  84. /** @type {IncomingConnections} */
  85. this.incomingConnections = new SortableSet();
  86. /** @type {OutgoingConnections | undefined} */
  87. this.outgoingConnections = undefined;
  88. /** @type {Issuer} */
  89. this.issuer = undefined;
  90. /** @type {OptimizationBailouts} */
  91. this.optimizationBailout = [];
  92. /** @type {ExportsInfo} */
  93. this.exports = new ExportsInfo();
  94. /** @type {number | null} */
  95. this.preOrderIndex = null;
  96. /** @type {number | null} */
  97. this.postOrderIndex = null;
  98. /** @type {number | null} */
  99. this.depth = null;
  100. /** @type {ModuleProfile | undefined} */
  101. this.profile = undefined;
  102. /** @type {boolean} */
  103. this.async = false;
  104. /** @type {ModuleGraphConnection[] | undefined} */
  105. this._unassignedConnections = undefined;
  106. }
  107. }
  108. /** @typedef {(moduleGraphConnection: ModuleGraphConnection) => boolean} FilterConnection */
  109. /** @typedef {EXPECTED_OBJECT} MetaKey */
  110. /** @typedef {import("./dependencies/CommonJsExportRequireDependency").idsSymbol} CommonJsExportRequireDependencyIDsSymbol */
  111. /** @typedef {import("./dependencies/HarmonyImportSpecifierDependency").idsSymbol} HarmonyImportSpecifierDependencyIDsSymbol */
  112. /** @typedef {import("./dependencies/HarmonyExportImportedSpecifierDependency").idsSymbol} HarmonyExportImportedSpecifierDependencyIDsSymbol */
  113. /**
  114. * @typedef {object} KnownMeta
  115. * @property {Map<Module, string>=} importVarMap
  116. * @property {Map<Module, string>=} deferredImportVarMap
  117. */
  118. /** @typedef {KnownMeta & Record<CommonJsExportRequireDependencyIDsSymbol | HarmonyImportSpecifierDependencyIDsSymbol | HarmonyExportImportedSpecifierDependencyIDsSymbol, string[]> & Record<string, EXPECTED_ANY>} Meta */
  119. class ModuleGraph {
  120. constructor() {
  121. /**
  122. * @type {WeakMap<Dependency, ModuleGraphConnection | null>}
  123. * @private
  124. */
  125. this._dependencyMap = new WeakMap();
  126. /**
  127. * @type {Map<Module, ModuleGraphModule>}
  128. * @private
  129. */
  130. this._moduleMap = new Map();
  131. /**
  132. * @type {WeakMap<MetaKey, Meta>}
  133. * @private
  134. */
  135. this._metaMap = new WeakMap();
  136. /**
  137. * @type {WeakTupleMap<EXPECTED_ANY[], EXPECTED_ANY> | undefined}
  138. * @private
  139. */
  140. this._cache = undefined;
  141. /**
  142. * @type {ModuleMemCaches | undefined}
  143. * @private
  144. */
  145. this._moduleMemCaches = undefined;
  146. /**
  147. * @type {string | undefined}
  148. * @private
  149. */
  150. this._cacheStage = undefined;
  151. /**
  152. * @type {WeakMap<Dependency, DependencySourceOrder>}
  153. * @private
  154. */
  155. this._dependencySourceOrderMap = new WeakMap();
  156. /**
  157. * @type {Set<Module>}
  158. * @private
  159. */
  160. this._modulesNeedingSort = new Set();
  161. }
  162. /**
  163. * @param {Module} module the module
  164. * @returns {ModuleGraphModule} the internal module
  165. */
  166. _getModuleGraphModule(module) {
  167. let mgm = this._moduleMap.get(module);
  168. if (mgm === undefined) {
  169. mgm = new ModuleGraphModule();
  170. this._moduleMap.set(module, mgm);
  171. }
  172. return mgm;
  173. }
  174. /**
  175. * @param {Dependency} dependency the dependency
  176. * @param {DependenciesBlock} block parent block
  177. * @param {Module} module parent module
  178. * @param {number=} indexInBlock position in block
  179. * @returns {void}
  180. */
  181. setParents(dependency, block, module, indexInBlock = -1) {
  182. dependency._parentDependenciesBlockIndex = indexInBlock;
  183. dependency._parentDependenciesBlock = block;
  184. dependency._parentModule = module;
  185. }
  186. /**
  187. * @param {Dependency} dependency the dependency
  188. * @param {number} index the index
  189. * @returns {void}
  190. */
  191. setParentDependenciesBlockIndex(dependency, index) {
  192. dependency._parentDependenciesBlockIndex = index;
  193. }
  194. /**
  195. * @param {Dependency} dependency the dependency
  196. * @returns {Module | undefined} parent module
  197. */
  198. getParentModule(dependency) {
  199. return dependency._parentModule;
  200. }
  201. /**
  202. * @param {Dependency} dependency the dependency
  203. * @returns {DependenciesBlock | undefined} parent block
  204. */
  205. getParentBlock(dependency) {
  206. return dependency._parentDependenciesBlock;
  207. }
  208. /**
  209. * @param {Dependency} dependency the dependency
  210. * @returns {number} index
  211. */
  212. getParentBlockIndex(dependency) {
  213. return dependency._parentDependenciesBlockIndex;
  214. }
  215. /**
  216. * @param {Module | null} originModule the referencing module
  217. * @param {Dependency} dependency the referencing dependency
  218. * @param {Module} module the referenced module
  219. * @returns {void}
  220. */
  221. setResolvedModule(originModule, dependency, module) {
  222. const connection = new ModuleGraphConnection(
  223. originModule,
  224. dependency,
  225. module,
  226. undefined,
  227. dependency.weak,
  228. dependency.getCondition(this)
  229. );
  230. const connections = this._getModuleGraphModule(module).incomingConnections;
  231. connections.add(connection);
  232. if (originModule) {
  233. const mgm = this._getModuleGraphModule(originModule);
  234. if (mgm._unassignedConnections === undefined) {
  235. mgm._unassignedConnections = [];
  236. }
  237. mgm._unassignedConnections.push(connection);
  238. if (mgm.outgoingConnections === undefined) {
  239. mgm.outgoingConnections = new SortableSet();
  240. }
  241. mgm.outgoingConnections.add(connection);
  242. } else {
  243. this._dependencyMap.set(dependency, connection);
  244. }
  245. }
  246. /**
  247. * @param {Dependency} dependency the referencing dependency
  248. * @param {Module} module the referenced module
  249. * @returns {void}
  250. */
  251. updateModule(dependency, module) {
  252. const connection =
  253. /** @type {ModuleGraphConnection} */
  254. (this.getConnection(dependency));
  255. if (connection.module === module) return;
  256. const newConnection = connection.clone();
  257. newConnection.module = module;
  258. this._dependencyMap.set(dependency, newConnection);
  259. connection.setActive(false);
  260. const originMgm = this._getModuleGraphModule(
  261. /** @type {Module} */ (connection.originModule)
  262. );
  263. /** @type {OutgoingConnections} */
  264. (originMgm.outgoingConnections).add(newConnection);
  265. const targetMgm = this._getModuleGraphModule(module);
  266. targetMgm.incomingConnections.add(newConnection);
  267. }
  268. /**
  269. * @param {Dependency} dependency the need update dependency
  270. * @param {ModuleGraphConnection=} connection the target connection
  271. * @param {Module=} parentModule the parent module
  272. * @returns {void}
  273. */
  274. updateParent(dependency, connection, parentModule) {
  275. if (this._dependencySourceOrderMap.has(dependency)) {
  276. return;
  277. }
  278. if (!connection || !parentModule) {
  279. return;
  280. }
  281. const originDependency = connection.dependency;
  282. // src/index.js
  283. // import { c } from "lib/c" -> c = 0
  284. // import { a, b } from "lib" -> a and b have the same source order -> a = b = 1
  285. // import { d } from "lib/d" -> d = 2
  286. const currentSourceOrder =
  287. /** @type {HarmonyImportSideEffectDependency | HarmonyImportSpecifierDependency} */
  288. (dependency).sourceOrder;
  289. // lib/index.js (reexport)
  290. // import { a } from "lib/a" -> a = 0
  291. // import { b } from "lib/b" -> b = 1
  292. const originSourceOrder =
  293. /** @type {HarmonyImportSideEffectDependency | HarmonyImportSpecifierDependency} */
  294. (originDependency).sourceOrder;
  295. if (
  296. typeof currentSourceOrder === "number" &&
  297. typeof originSourceOrder === "number"
  298. ) {
  299. // src/index.js
  300. // import { c } from "lib/c" -> c = 0
  301. // import { a } from "lib/a" -> a = 1.0 = 1(main) + 0.0(sub)
  302. // import { b } from "lib/b" -> b = 1.1 = 1(main) + 0.1(sub)
  303. // import { d } from "lib/d" -> d = 2
  304. this._dependencySourceOrderMap.set(dependency, {
  305. main: currentSourceOrder,
  306. sub: originSourceOrder
  307. });
  308. // Save for later batch sorting
  309. this._modulesNeedingSort.add(parentModule);
  310. }
  311. }
  312. /**
  313. * @returns {void}
  314. */
  315. finishUpdateParent() {
  316. if (this._modulesNeedingSort.size === 0) {
  317. return;
  318. }
  319. for (const mod of this._modulesNeedingSort) {
  320. // If dependencies like HarmonyImportSideEffectDependency and HarmonyImportSpecifierDependency have a SourceOrder,
  321. // we sort based on it; otherwise, we preserve the original order.
  322. sortWithSourceOrder(
  323. mod.dependencies,
  324. this._dependencySourceOrderMap,
  325. (dep, index) => this.setParentDependenciesBlockIndex(dep, index)
  326. );
  327. }
  328. this._modulesNeedingSort.clear();
  329. }
  330. /**
  331. * @param {Dependency} dependency the referencing dependency
  332. * @returns {void}
  333. */
  334. removeConnection(dependency) {
  335. const connection =
  336. /** @type {ModuleGraphConnection} */
  337. (this.getConnection(dependency));
  338. const targetMgm = this._getModuleGraphModule(connection.module);
  339. targetMgm.incomingConnections.delete(connection);
  340. const originMgm = this._getModuleGraphModule(
  341. /** @type {Module} */ (connection.originModule)
  342. );
  343. /** @type {OutgoingConnections} */
  344. (originMgm.outgoingConnections).delete(connection);
  345. this._dependencyMap.set(dependency, null);
  346. }
  347. /**
  348. * @param {Dependency} dependency the referencing dependency
  349. * @param {string} explanation an explanation
  350. * @returns {void}
  351. */
  352. addExplanation(dependency, explanation) {
  353. const connection =
  354. /** @type {ModuleGraphConnection} */
  355. (this.getConnection(dependency));
  356. connection.addExplanation(explanation);
  357. }
  358. /**
  359. * @param {Module} sourceModule the source module
  360. * @param {Module} targetModule the target module
  361. * @returns {void}
  362. */
  363. cloneModuleAttributes(sourceModule, targetModule) {
  364. const oldMgm = this._getModuleGraphModule(sourceModule);
  365. const newMgm = this._getModuleGraphModule(targetModule);
  366. newMgm.postOrderIndex = oldMgm.postOrderIndex;
  367. newMgm.preOrderIndex = oldMgm.preOrderIndex;
  368. newMgm.depth = oldMgm.depth;
  369. newMgm.exports = oldMgm.exports;
  370. newMgm.async = oldMgm.async;
  371. }
  372. /**
  373. * @param {Module} module the module
  374. * @returns {void}
  375. */
  376. removeModuleAttributes(module) {
  377. const mgm = this._getModuleGraphModule(module);
  378. mgm.postOrderIndex = null;
  379. mgm.preOrderIndex = null;
  380. mgm.depth = null;
  381. mgm.async = false;
  382. }
  383. /**
  384. * @returns {void}
  385. */
  386. removeAllModuleAttributes() {
  387. for (const mgm of this._moduleMap.values()) {
  388. mgm.postOrderIndex = null;
  389. mgm.preOrderIndex = null;
  390. mgm.depth = null;
  391. mgm.async = false;
  392. }
  393. }
  394. /**
  395. * @param {Module} oldModule the old referencing module
  396. * @param {Module} newModule the new referencing module
  397. * @param {FilterConnection} filterConnection filter predicate for replacement
  398. * @returns {void}
  399. */
  400. moveModuleConnections(oldModule, newModule, filterConnection) {
  401. if (oldModule === newModule) return;
  402. const oldMgm = this._getModuleGraphModule(oldModule);
  403. const newMgm = this._getModuleGraphModule(newModule);
  404. // Outgoing connections
  405. const oldConnections = oldMgm.outgoingConnections;
  406. if (oldConnections !== undefined) {
  407. if (newMgm.outgoingConnections === undefined) {
  408. newMgm.outgoingConnections = new SortableSet();
  409. }
  410. const newConnections = newMgm.outgoingConnections;
  411. for (const connection of oldConnections) {
  412. if (filterConnection(connection)) {
  413. connection.originModule = newModule;
  414. newConnections.add(connection);
  415. oldConnections.delete(connection);
  416. }
  417. }
  418. }
  419. // Incoming connections
  420. const oldConnections2 = oldMgm.incomingConnections;
  421. const newConnections2 = newMgm.incomingConnections;
  422. for (const connection of oldConnections2) {
  423. if (filterConnection(connection)) {
  424. connection.module = newModule;
  425. newConnections2.add(connection);
  426. oldConnections2.delete(connection);
  427. }
  428. }
  429. }
  430. /**
  431. * @param {Module} oldModule the old referencing module
  432. * @param {Module} newModule the new referencing module
  433. * @param {FilterConnection} filterConnection filter predicate for replacement
  434. * @returns {void}
  435. */
  436. copyOutgoingModuleConnections(oldModule, newModule, filterConnection) {
  437. if (oldModule === newModule) return;
  438. const oldMgm = this._getModuleGraphModule(oldModule);
  439. const newMgm = this._getModuleGraphModule(newModule);
  440. // Outgoing connections
  441. const oldConnections = oldMgm.outgoingConnections;
  442. if (oldConnections !== undefined) {
  443. if (newMgm.outgoingConnections === undefined) {
  444. newMgm.outgoingConnections = new SortableSet();
  445. }
  446. const newConnections = newMgm.outgoingConnections;
  447. for (const connection of oldConnections) {
  448. if (filterConnection(connection)) {
  449. const newConnection = connection.clone();
  450. newConnection.originModule = newModule;
  451. newConnections.add(newConnection);
  452. if (newConnection.module !== undefined) {
  453. const otherMgm = this._getModuleGraphModule(newConnection.module);
  454. otherMgm.incomingConnections.add(newConnection);
  455. }
  456. }
  457. }
  458. }
  459. }
  460. /**
  461. * @param {Module} module the referenced module
  462. * @param {string} explanation an explanation why it's referenced
  463. * @returns {void}
  464. */
  465. addExtraReason(module, explanation) {
  466. const connections = this._getModuleGraphModule(module).incomingConnections;
  467. connections.add(new ModuleGraphConnection(null, null, module, explanation));
  468. }
  469. /**
  470. * @param {Dependency} dependency the dependency to look for a referenced module
  471. * @returns {Module | null} the referenced module
  472. */
  473. getResolvedModule(dependency) {
  474. const connection = this.getConnection(dependency);
  475. return connection !== undefined ? connection.resolvedModule : null;
  476. }
  477. /**
  478. * @param {Dependency} dependency the dependency to look for a referenced module
  479. * @returns {ModuleGraphConnection | undefined} the connection
  480. */
  481. getConnection(dependency) {
  482. const connection = this._dependencyMap.get(dependency);
  483. if (connection === undefined) {
  484. const module = this.getParentModule(dependency);
  485. if (module !== undefined) {
  486. const mgm = this._getModuleGraphModule(module);
  487. if (
  488. mgm._unassignedConnections &&
  489. mgm._unassignedConnections.length !== 0
  490. ) {
  491. /** @type {undefined | ModuleGraphConnection} */
  492. let foundConnection;
  493. for (const connection of mgm._unassignedConnections) {
  494. this._dependencyMap.set(
  495. /** @type {Dependency} */ (connection.dependency),
  496. connection
  497. );
  498. if (connection.dependency === dependency) {
  499. foundConnection = connection;
  500. }
  501. }
  502. mgm._unassignedConnections.length = 0;
  503. if (foundConnection !== undefined) {
  504. return foundConnection;
  505. }
  506. }
  507. }
  508. this._dependencyMap.set(dependency, null);
  509. return;
  510. }
  511. return connection === null ? undefined : connection;
  512. }
  513. /**
  514. * @param {Dependency} dependency the dependency to look for a referenced module
  515. * @returns {Module | null} the referenced module
  516. */
  517. getModule(dependency) {
  518. const connection = this.getConnection(dependency);
  519. return connection !== undefined ? connection.module : null;
  520. }
  521. /**
  522. * @param {Dependency} dependency the dependency to look for a referencing module
  523. * @returns {Module | null} the referencing module
  524. */
  525. getOrigin(dependency) {
  526. const connection = this.getConnection(dependency);
  527. return connection !== undefined ? connection.originModule : null;
  528. }
  529. /**
  530. * @param {Dependency} dependency the dependency to look for a referencing module
  531. * @returns {Module | null} the original referencing module
  532. */
  533. getResolvedOrigin(dependency) {
  534. const connection = this.getConnection(dependency);
  535. return connection !== undefined ? connection.resolvedOriginModule : null;
  536. }
  537. /**
  538. * @param {Module} module the module
  539. * @returns {Iterable<ModuleGraphConnection>} reasons why a module is included
  540. */
  541. getIncomingConnections(module) {
  542. const connections = this._getModuleGraphModule(module).incomingConnections;
  543. return connections;
  544. }
  545. /**
  546. * @param {Module} module the module
  547. * @returns {Iterable<ModuleGraphConnection>} list of outgoing connections
  548. */
  549. getOutgoingConnections(module) {
  550. const connections = this._getModuleGraphModule(module).outgoingConnections;
  551. return connections === undefined ? EMPTY_SET : connections;
  552. }
  553. /**
  554. * @param {Module} module the module
  555. * @returns {ReadonlyMap<Module | undefined | null, ReadonlyArray<ModuleGraphConnection>>} reasons why a module is included, in a map by source module
  556. */
  557. getIncomingConnectionsByOriginModule(module) {
  558. const connections = this._getModuleGraphModule(module).incomingConnections;
  559. return connections.getFromUnorderedCache(getConnectionsByOriginModule);
  560. }
  561. /**
  562. * @param {Module} module the module
  563. * @returns {ReadonlyMap<Module | undefined, ReadonlyArray<ModuleGraphConnection>> | undefined} connections to modules, in a map by module
  564. */
  565. getOutgoingConnectionsByModule(module) {
  566. const connections = this._getModuleGraphModule(module).outgoingConnections;
  567. return connections === undefined
  568. ? undefined
  569. : connections.getFromUnorderedCache(getConnectionsByModule);
  570. }
  571. /**
  572. * @param {Module} module the module
  573. * @returns {ModuleProfile | undefined} the module profile
  574. */
  575. getProfile(module) {
  576. const mgm = this._getModuleGraphModule(module);
  577. return mgm.profile;
  578. }
  579. /**
  580. * @param {Module} module the module
  581. * @param {ModuleProfile | undefined} profile the module profile
  582. * @returns {void}
  583. */
  584. setProfile(module, profile) {
  585. const mgm = this._getModuleGraphModule(module);
  586. mgm.profile = profile;
  587. }
  588. /**
  589. * @param {Module} module the module
  590. * @returns {Issuer} the issuer module
  591. */
  592. getIssuer(module) {
  593. const mgm = this._getModuleGraphModule(module);
  594. return mgm.issuer;
  595. }
  596. /**
  597. * @param {Module} module the module
  598. * @param {Module | null} issuer the issuer module
  599. * @returns {void}
  600. */
  601. setIssuer(module, issuer) {
  602. const mgm = this._getModuleGraphModule(module);
  603. mgm.issuer = issuer;
  604. }
  605. /**
  606. * @param {Module} module the module
  607. * @param {Module | null} issuer the issuer module
  608. * @returns {void}
  609. */
  610. setIssuerIfUnset(module, issuer) {
  611. const mgm = this._getModuleGraphModule(module);
  612. if (mgm.issuer === undefined) mgm.issuer = issuer;
  613. }
  614. /**
  615. * @param {Module} module the module
  616. * @returns {OptimizationBailouts} optimization bailouts
  617. */
  618. getOptimizationBailout(module) {
  619. const mgm = this._getModuleGraphModule(module);
  620. return mgm.optimizationBailout;
  621. }
  622. /**
  623. * @param {Module} module the module
  624. * @returns {null | true | ExportInfoName[]} the provided exports
  625. */
  626. getProvidedExports(module) {
  627. const mgm = this._getModuleGraphModule(module);
  628. return mgm.exports.getProvidedExports();
  629. }
  630. /**
  631. * @param {Module} module the module
  632. * @param {ExportInfoName | ExportInfoName[]} exportName a name of an export
  633. * @returns {boolean | null} true, if the export is provided by the module.
  634. * null, if it's unknown.
  635. * false, if it's not provided.
  636. */
  637. isExportProvided(module, exportName) {
  638. const mgm = this._getModuleGraphModule(module);
  639. const result = mgm.exports.isExportProvided(exportName);
  640. return result === undefined ? null : result;
  641. }
  642. /**
  643. * @param {Module} module the module
  644. * @returns {ExportsInfo} info about the exports
  645. */
  646. getExportsInfo(module) {
  647. const mgm = this._getModuleGraphModule(module);
  648. return mgm.exports;
  649. }
  650. /**
  651. * @param {Module} module the module
  652. * @param {string} exportName the export
  653. * @returns {ExportInfo} info about the export
  654. */
  655. getExportInfo(module, exportName) {
  656. const mgm = this._getModuleGraphModule(module);
  657. return mgm.exports.getExportInfo(exportName);
  658. }
  659. /**
  660. * @param {Module} module the module
  661. * @param {string} exportName the export
  662. * @returns {ExportInfo} info about the export (do not modify)
  663. */
  664. getReadOnlyExportInfo(module, exportName) {
  665. const mgm = this._getModuleGraphModule(module);
  666. return mgm.exports.getReadOnlyExportInfo(exportName);
  667. }
  668. /**
  669. * @param {Module} module the module
  670. * @param {RuntimeSpec} runtime the runtime
  671. * @returns {false | true | SortableSet<string> | null} the used exports
  672. * false: module is not used at all.
  673. * true: the module namespace/object export is used.
  674. * SortableSet<string>: these export names are used.
  675. * empty SortableSet<string>: module is used but no export.
  676. * null: unknown, worst case should be assumed.
  677. */
  678. getUsedExports(module, runtime) {
  679. const mgm = this._getModuleGraphModule(module);
  680. return mgm.exports.getUsedExports(runtime);
  681. }
  682. /**
  683. * @param {Module} module the module
  684. * @returns {number | null} the index of the module
  685. */
  686. getPreOrderIndex(module) {
  687. const mgm = this._getModuleGraphModule(module);
  688. return mgm.preOrderIndex;
  689. }
  690. /**
  691. * @param {Module} module the module
  692. * @returns {number | null} the index of the module
  693. */
  694. getPostOrderIndex(module) {
  695. const mgm = this._getModuleGraphModule(module);
  696. return mgm.postOrderIndex;
  697. }
  698. /**
  699. * @param {Module} module the module
  700. * @param {number} index the index of the module
  701. * @returns {void}
  702. */
  703. setPreOrderIndex(module, index) {
  704. const mgm = this._getModuleGraphModule(module);
  705. mgm.preOrderIndex = index;
  706. }
  707. /**
  708. * @param {Module} module the module
  709. * @param {number} index the index of the module
  710. * @returns {boolean} true, if the index was set
  711. */
  712. setPreOrderIndexIfUnset(module, index) {
  713. const mgm = this._getModuleGraphModule(module);
  714. if (mgm.preOrderIndex === null) {
  715. mgm.preOrderIndex = index;
  716. return true;
  717. }
  718. return false;
  719. }
  720. /**
  721. * @param {Module} module the module
  722. * @param {number} index the index of the module
  723. * @returns {void}
  724. */
  725. setPostOrderIndex(module, index) {
  726. const mgm = this._getModuleGraphModule(module);
  727. mgm.postOrderIndex = index;
  728. }
  729. /**
  730. * @param {Module} module the module
  731. * @param {number} index the index of the module
  732. * @returns {boolean} true, if the index was set
  733. */
  734. setPostOrderIndexIfUnset(module, index) {
  735. const mgm = this._getModuleGraphModule(module);
  736. if (mgm.postOrderIndex === null) {
  737. mgm.postOrderIndex = index;
  738. return true;
  739. }
  740. return false;
  741. }
  742. /**
  743. * @param {Module} module the module
  744. * @returns {number | null} the depth of the module
  745. */
  746. getDepth(module) {
  747. const mgm = this._getModuleGraphModule(module);
  748. return mgm.depth;
  749. }
  750. /**
  751. * @param {Module} module the module
  752. * @param {number} depth the depth of the module
  753. * @returns {void}
  754. */
  755. setDepth(module, depth) {
  756. const mgm = this._getModuleGraphModule(module);
  757. mgm.depth = depth;
  758. }
  759. /**
  760. * @param {Module} module the module
  761. * @param {number} depth the depth of the module
  762. * @returns {boolean} true, if the depth was set
  763. */
  764. setDepthIfLower(module, depth) {
  765. const mgm = this._getModuleGraphModule(module);
  766. if (mgm.depth === null || mgm.depth > depth) {
  767. mgm.depth = depth;
  768. return true;
  769. }
  770. return false;
  771. }
  772. /**
  773. * @param {Module} module the module
  774. * @returns {boolean} true, if the module is async
  775. */
  776. isAsync(module) {
  777. const mgm = this._getModuleGraphModule(module);
  778. return mgm.async;
  779. }
  780. /**
  781. * @param {Module} module the module
  782. * @returns {boolean} true, if the module is used as a deferred module at least once
  783. */
  784. isDeferred(module) {
  785. if (this.isAsync(module)) return false;
  786. const connections = this.getIncomingConnections(module);
  787. for (const connection of connections) {
  788. if (
  789. !connection.dependency ||
  790. !(connection.dependency instanceof HarmonyImportDependency)
  791. ) {
  792. continue;
  793. }
  794. if (ImportPhaseUtils.isDefer(connection.dependency.phase)) return true;
  795. }
  796. return false;
  797. }
  798. /**
  799. * @param {Module} module the module
  800. * @returns {void}
  801. */
  802. setAsync(module) {
  803. const mgm = this._getModuleGraphModule(module);
  804. mgm.async = true;
  805. }
  806. /**
  807. * @param {MetaKey} thing any thing
  808. * @returns {Meta} metadata
  809. */
  810. getMeta(thing) {
  811. let meta = this._metaMap.get(thing);
  812. if (meta === undefined) {
  813. meta = /** @type {Meta} */ (Object.create(null));
  814. this._metaMap.set(thing, meta);
  815. }
  816. return meta;
  817. }
  818. /**
  819. * @param {MetaKey} thing any thing
  820. * @returns {Meta | undefined} metadata
  821. */
  822. getMetaIfExisting(thing) {
  823. return this._metaMap.get(thing);
  824. }
  825. /**
  826. * @param {string=} cacheStage a persistent stage name for caching
  827. */
  828. freeze(cacheStage) {
  829. this._cache = new WeakTupleMap();
  830. this._cacheStage = cacheStage;
  831. }
  832. unfreeze() {
  833. this._cache = undefined;
  834. this._cacheStage = undefined;
  835. }
  836. /**
  837. * @template {EXPECTED_ANY[]} T
  838. * @template R
  839. * @param {(moduleGraph: ModuleGraph, ...args: T) => R} fn computer
  840. * @param {T} args arguments
  841. * @returns {R} computed value or cached
  842. */
  843. cached(fn, ...args) {
  844. if (this._cache === undefined) return fn(this, ...args);
  845. return this._cache.provide(fn, ...args, () => fn(this, ...args));
  846. }
  847. /**
  848. * @param {ModuleMemCaches} moduleMemCaches mem caches for modules for better caching
  849. */
  850. setModuleMemCaches(moduleMemCaches) {
  851. this._moduleMemCaches = moduleMemCaches;
  852. }
  853. /**
  854. * @template {Dependency} D
  855. * @template {EXPECTED_ANY[]} ARGS
  856. * @template R
  857. * @param {D} dependency dependency
  858. * @param {[...ARGS, (moduleGraph: ModuleGraph, dependency: D, ...args: ARGS) => R]} args arguments, last argument is a function called with moduleGraph, dependency, ...args
  859. * @returns {R} computed value or cached
  860. */
  861. dependencyCacheProvide(dependency, ...args) {
  862. const fn =
  863. /** @type {(moduleGraph: ModuleGraph, dependency: D, ...args: EXPECTED_ANY[]) => R} */
  864. (args.pop());
  865. if (this._moduleMemCaches && this._cacheStage) {
  866. const memCache = this._moduleMemCaches.get(
  867. /** @type {Module} */
  868. (this.getParentModule(dependency))
  869. );
  870. if (memCache !== undefined) {
  871. return memCache.provide(dependency, this._cacheStage, ...args, () =>
  872. fn(this, dependency, ...args)
  873. );
  874. }
  875. }
  876. if (this._cache === undefined) return fn(this, dependency, ...args);
  877. return this._cache.provide(dependency, ...args, () =>
  878. fn(this, dependency, ...args)
  879. );
  880. }
  881. // TODO remove in webpack 6
  882. /**
  883. * @param {Module} module the module
  884. * @param {string} deprecateMessage message for the deprecation message
  885. * @param {string} deprecationCode code for the deprecation
  886. * @returns {ModuleGraph} the module graph
  887. */
  888. static getModuleGraphForModule(module, deprecateMessage, deprecationCode) {
  889. const fn = deprecateMap.get(deprecateMessage);
  890. if (fn) return fn(module);
  891. const newFn = util.deprecate(
  892. /**
  893. * @param {Module} module the module
  894. * @returns {ModuleGraph} the module graph
  895. */
  896. (module) => {
  897. const moduleGraph = moduleGraphForModuleMap.get(module);
  898. if (!moduleGraph) {
  899. throw new Error(
  900. `${
  901. deprecateMessage
  902. }There was no ModuleGraph assigned to the Module for backward-compat (Use the new API)`
  903. );
  904. }
  905. return moduleGraph;
  906. },
  907. `${deprecateMessage}: Use new ModuleGraph API`,
  908. deprecationCode
  909. );
  910. deprecateMap.set(deprecateMessage, newFn);
  911. return newFn(module);
  912. }
  913. // TODO remove in webpack 6
  914. /**
  915. * @param {Module} module the module
  916. * @param {ModuleGraph} moduleGraph the module graph
  917. * @returns {void}
  918. */
  919. static setModuleGraphForModule(module, moduleGraph) {
  920. moduleGraphForModuleMap.set(module, moduleGraph);
  921. }
  922. // TODO remove in webpack 6
  923. /**
  924. * @param {Module} module the module
  925. * @returns {void}
  926. */
  927. static clearModuleGraphForModule(module) {
  928. moduleGraphForModuleMap.delete(module);
  929. }
  930. }
  931. // TODO remove in webpack 6
  932. /** @type {WeakMap<Module, ModuleGraph>} */
  933. const moduleGraphForModuleMap = new WeakMap();
  934. // TODO remove in webpack 6
  935. /** @type {Map<string, (module: Module) => ModuleGraph>} */
  936. const deprecateMap = new Map();
  937. module.exports = ModuleGraph;
  938. module.exports.ModuleGraphConnection = ModuleGraphConnection;