OccurrenceModuleIdsPlugin.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const {
  7. compareModulesByPreOrderIndexOrIdentifier
  8. } = require("../util/comparators");
  9. const createSchemaValidation = require("../util/create-schema-validation");
  10. const {
  11. assignAscendingModuleIds,
  12. getUsedModuleIdsAndModules
  13. } = require("./IdHelpers");
  14. /** @typedef {import("../../declarations/plugins/ids/OccurrenceModuleIdsPlugin").OccurrenceModuleIdsPluginOptions} OccurrenceModuleIdsPluginOptions */
  15. /** @typedef {import("../Compiler")} Compiler */
  16. /** @typedef {import("../Module")} Module */
  17. /** @typedef {import("../ModuleGraphConnection")} ModuleGraphConnection */
  18. const validate = createSchemaValidation(
  19. require("../../schemas/plugins/ids/OccurrenceModuleIdsPlugin.check.js"),
  20. () => require("../../schemas/plugins/ids/OccurrenceModuleIdsPlugin.json"),
  21. {
  22. name: "Occurrence Order Module Ids Plugin",
  23. baseDataPath: "options"
  24. }
  25. );
  26. class OccurrenceModuleIdsPlugin {
  27. /**
  28. * @param {OccurrenceModuleIdsPluginOptions=} options options object
  29. */
  30. constructor(options = {}) {
  31. validate(options);
  32. this.options = options;
  33. }
  34. /**
  35. * Apply the plugin
  36. * @param {Compiler} compiler the compiler instance
  37. * @returns {void}
  38. */
  39. apply(compiler) {
  40. const prioritiseInitial = this.options.prioritiseInitial;
  41. compiler.hooks.compilation.tap("OccurrenceModuleIdsPlugin", compilation => {
  42. const moduleGraph = compilation.moduleGraph;
  43. compilation.hooks.moduleIds.tap("OccurrenceModuleIdsPlugin", () => {
  44. const chunkGraph = compilation.chunkGraph;
  45. const [usedIds, modulesInOccurrenceOrder] =
  46. getUsedModuleIdsAndModules(compilation);
  47. const occursInInitialChunksMap = new Map();
  48. const occursInAllChunksMap = new Map();
  49. const initialChunkChunkMap = new Map();
  50. const entryCountMap = new Map();
  51. for (const m of modulesInOccurrenceOrder) {
  52. let initial = 0;
  53. let entry = 0;
  54. for (const c of chunkGraph.getModuleChunksIterable(m)) {
  55. if (c.canBeInitial()) initial++;
  56. if (chunkGraph.isEntryModuleInChunk(m, c)) entry++;
  57. }
  58. initialChunkChunkMap.set(m, initial);
  59. entryCountMap.set(m, entry);
  60. }
  61. /**
  62. * @param {Module} module module
  63. * @returns {number} count of occurs
  64. */
  65. const countOccursInEntry = module => {
  66. let sum = 0;
  67. for (const [
  68. originModule,
  69. connections
  70. ] of moduleGraph.getIncomingConnectionsByOriginModule(module)) {
  71. if (!originModule) continue;
  72. if (!connections.some(c => c.isTargetActive(undefined))) continue;
  73. sum += initialChunkChunkMap.get(originModule);
  74. }
  75. return sum;
  76. };
  77. /**
  78. * @param {Module} module module
  79. * @returns {number} count of occurs
  80. */
  81. const countOccurs = module => {
  82. let sum = 0;
  83. for (const [
  84. originModule,
  85. connections
  86. ] of moduleGraph.getIncomingConnectionsByOriginModule(module)) {
  87. if (!originModule) continue;
  88. const chunkModules =
  89. chunkGraph.getNumberOfModuleChunks(originModule);
  90. for (const c of connections) {
  91. if (!c.isTargetActive(undefined)) continue;
  92. if (!c.dependency) continue;
  93. const factor = c.dependency.getNumberOfIdOccurrences();
  94. if (factor === 0) continue;
  95. sum += factor * chunkModules;
  96. }
  97. }
  98. return sum;
  99. };
  100. if (prioritiseInitial) {
  101. for (const m of modulesInOccurrenceOrder) {
  102. const result =
  103. countOccursInEntry(m) +
  104. initialChunkChunkMap.get(m) +
  105. entryCountMap.get(m);
  106. occursInInitialChunksMap.set(m, result);
  107. }
  108. }
  109. for (const m of modulesInOccurrenceOrder) {
  110. const result =
  111. countOccurs(m) +
  112. chunkGraph.getNumberOfModuleChunks(m) +
  113. entryCountMap.get(m);
  114. occursInAllChunksMap.set(m, result);
  115. }
  116. const naturalCompare = compareModulesByPreOrderIndexOrIdentifier(
  117. compilation.moduleGraph
  118. );
  119. modulesInOccurrenceOrder.sort((a, b) => {
  120. if (prioritiseInitial) {
  121. const aEntryOccurs = occursInInitialChunksMap.get(a);
  122. const bEntryOccurs = occursInInitialChunksMap.get(b);
  123. if (aEntryOccurs > bEntryOccurs) return -1;
  124. if (aEntryOccurs < bEntryOccurs) return 1;
  125. }
  126. const aOccurs = occursInAllChunksMap.get(a);
  127. const bOccurs = occursInAllChunksMap.get(b);
  128. if (aOccurs > bOccurs) return -1;
  129. if (aOccurs < bOccurs) return 1;
  130. return naturalCompare(a, b);
  131. });
  132. assignAscendingModuleIds(
  133. usedIds,
  134. modulesInOccurrenceOrder,
  135. compilation
  136. );
  137. });
  138. });
  139. }
  140. }
  141. module.exports = OccurrenceModuleIdsPlugin;