ModuleGraph.js 28 KB

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