OccurrenceModuleIdsPlugin.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  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. const PLUGIN_NAME = "OccurrenceModuleIdsPlugin";
  27. class OccurrenceModuleIdsPlugin {
  28. /**
  29. * @param {OccurrenceModuleIdsPluginOptions=} options options object
  30. */
  31. constructor(options = {}) {
  32. validate(options);
  33. this.options = options;
  34. }
  35. /**
  36. * Apply the plugin
  37. * @param {Compiler} compiler the compiler instance
  38. * @returns {void}
  39. */
  40. apply(compiler) {
  41. const prioritiseInitial = this.options.prioritiseInitial;
  42. compiler.hooks.compilation.tap(PLUGIN_NAME, compilation => {
  43. const moduleGraph = compilation.moduleGraph;
  44. compilation.hooks.moduleIds.tap(PLUGIN_NAME, () => {
  45. const chunkGraph = compilation.chunkGraph;
  46. const [usedIds, modulesInOccurrenceOrder] =
  47. getUsedModuleIdsAndModules(compilation);
  48. const occursInInitialChunksMap = new Map();
  49. const occursInAllChunksMap = new Map();
  50. const initialChunkChunkMap = new Map();
  51. const entryCountMap = new Map();
  52. for (const m of modulesInOccurrenceOrder) {
  53. let initial = 0;
  54. let entry = 0;
  55. for (const c of chunkGraph.getModuleChunksIterable(m)) {
  56. if (c.canBeInitial()) initial++;
  57. if (chunkGraph.isEntryModuleInChunk(m, c)) entry++;
  58. }
  59. initialChunkChunkMap.set(m, initial);
  60. entryCountMap.set(m, entry);
  61. }
  62. /**
  63. * @param {Module} module module
  64. * @returns {number} count of occurs
  65. */
  66. const countOccursInEntry = module => {
  67. let sum = 0;
  68. for (const [
  69. originModule,
  70. connections
  71. ] of moduleGraph.getIncomingConnectionsByOriginModule(module)) {
  72. if (!originModule) continue;
  73. if (!connections.some(c => c.isTargetActive(undefined))) continue;
  74. sum += initialChunkChunkMap.get(originModule) || 0;
  75. }
  76. return sum;
  77. };
  78. /**
  79. * @param {Module} module module
  80. * @returns {number} count of occurs
  81. */
  82. const countOccurs = module => {
  83. let sum = 0;
  84. for (const [
  85. originModule,
  86. connections
  87. ] of moduleGraph.getIncomingConnectionsByOriginModule(module)) {
  88. if (!originModule) continue;
  89. const chunkModules =
  90. chunkGraph.getNumberOfModuleChunks(originModule);
  91. for (const c of connections) {
  92. if (!c.isTargetActive(undefined)) continue;
  93. if (!c.dependency) continue;
  94. const factor = c.dependency.getNumberOfIdOccurrences();
  95. if (factor === 0) continue;
  96. sum += factor * chunkModules;
  97. }
  98. }
  99. return sum;
  100. };
  101. if (prioritiseInitial) {
  102. for (const m of modulesInOccurrenceOrder) {
  103. const result =
  104. countOccursInEntry(m) +
  105. initialChunkChunkMap.get(m) +
  106. entryCountMap.get(m);
  107. occursInInitialChunksMap.set(m, result);
  108. }
  109. }
  110. for (const m of modulesInOccurrenceOrder) {
  111. const result =
  112. countOccurs(m) +
  113. chunkGraph.getNumberOfModuleChunks(m) +
  114. entryCountMap.get(m);
  115. occursInAllChunksMap.set(m, result);
  116. }
  117. const naturalCompare = compareModulesByPreOrderIndexOrIdentifier(
  118. compilation.moduleGraph
  119. );
  120. modulesInOccurrenceOrder.sort((a, b) => {
  121. if (prioritiseInitial) {
  122. const aEntryOccurs = occursInInitialChunksMap.get(a);
  123. const bEntryOccurs = occursInInitialChunksMap.get(b);
  124. if (aEntryOccurs > bEntryOccurs) return -1;
  125. if (aEntryOccurs < bEntryOccurs) return 1;
  126. }
  127. const aOccurs = occursInAllChunksMap.get(a);
  128. const bOccurs = occursInAllChunksMap.get(b);
  129. if (aOccurs > bOccurs) return -1;
  130. if (aOccurs < bOccurs) return 1;
  131. return naturalCompare(a, b);
  132. });
  133. assignAscendingModuleIds(
  134. usedIds,
  135. modulesInOccurrenceOrder,
  136. compilation
  137. );
  138. });
  139. });
  140. }
  141. }
  142. module.exports = OccurrenceModuleIdsPlugin;