OccurrenceOrderPlugin.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. // TODO webpack 5 remove this plugin
  7. // It has been splitted into separate plugins for modules and chunks
  8. class OccurrenceOrderPlugin {
  9. constructor(preferEntry) {
  10. if (preferEntry !== undefined && typeof preferEntry !== "boolean") {
  11. throw new Error(
  12. "Argument should be a boolean.\nFor more info on this plugin, see https://webpack.js.org/plugins/"
  13. );
  14. }
  15. this.preferEntry = preferEntry;
  16. }
  17. apply(compiler) {
  18. const preferEntry = this.preferEntry;
  19. compiler.hooks.compilation.tap("OccurrenceOrderPlugin", compilation => {
  20. compilation.hooks.optimizeModuleOrder.tap(
  21. "OccurrenceOrderPlugin",
  22. modules => {
  23. const occursInInitialChunksMap = new Map();
  24. const occursInAllChunksMap = new Map();
  25. const initialChunkChunkMap = new Map();
  26. const entryCountMap = new Map();
  27. for (const m of modules) {
  28. let initial = 0;
  29. let entry = 0;
  30. for (const c of m.chunksIterable) {
  31. if (c.canBeInitial()) initial++;
  32. if (c.entryModule === m) entry++;
  33. }
  34. initialChunkChunkMap.set(m, initial);
  35. entryCountMap.set(m, entry);
  36. }
  37. const countOccursInEntry = (sum, r) => {
  38. if (!r.module) {
  39. return sum;
  40. }
  41. return sum + initialChunkChunkMap.get(r.module);
  42. };
  43. const countOccurs = (sum, r) => {
  44. if (!r.module) {
  45. return sum;
  46. }
  47. let factor = 1;
  48. if (typeof r.dependency.getNumberOfIdOccurrences === "function") {
  49. factor = r.dependency.getNumberOfIdOccurrences();
  50. }
  51. if (factor === 0) {
  52. return sum;
  53. }
  54. return sum + factor * r.module.getNumberOfChunks();
  55. };
  56. if (preferEntry) {
  57. for (const m of modules) {
  58. const result =
  59. m.reasons.reduce(countOccursInEntry, 0) +
  60. initialChunkChunkMap.get(m) +
  61. entryCountMap.get(m);
  62. occursInInitialChunksMap.set(m, result);
  63. }
  64. }
  65. const originalOrder = new Map();
  66. let i = 0;
  67. for (const m of modules) {
  68. const result =
  69. m.reasons.reduce(countOccurs, 0) +
  70. m.getNumberOfChunks() +
  71. entryCountMap.get(m);
  72. occursInAllChunksMap.set(m, result);
  73. originalOrder.set(m, i++);
  74. }
  75. modules.sort((a, b) => {
  76. if (preferEntry) {
  77. const aEntryOccurs = occursInInitialChunksMap.get(a);
  78. const bEntryOccurs = occursInInitialChunksMap.get(b);
  79. if (aEntryOccurs > bEntryOccurs) return -1;
  80. if (aEntryOccurs < bEntryOccurs) return 1;
  81. }
  82. const aOccurs = occursInAllChunksMap.get(a);
  83. const bOccurs = occursInAllChunksMap.get(b);
  84. if (aOccurs > bOccurs) return -1;
  85. if (aOccurs < bOccurs) return 1;
  86. const orgA = originalOrder.get(a);
  87. const orgB = originalOrder.get(b);
  88. return orgA - orgB;
  89. });
  90. }
  91. );
  92. compilation.hooks.optimizeChunkOrder.tap(
  93. "OccurrenceOrderPlugin",
  94. chunks => {
  95. const occursInInitialChunksMap = new Map();
  96. const originalOrder = new Map();
  97. let i = 0;
  98. for (const c of chunks) {
  99. let occurs = 0;
  100. for (const chunkGroup of c.groupsIterable) {
  101. for (const parent of chunkGroup.parentsIterable) {
  102. if (parent.isInitial()) occurs++;
  103. }
  104. }
  105. occursInInitialChunksMap.set(c, occurs);
  106. originalOrder.set(c, i++);
  107. }
  108. chunks.sort((a, b) => {
  109. const aEntryOccurs = occursInInitialChunksMap.get(a);
  110. const bEntryOccurs = occursInInitialChunksMap.get(b);
  111. if (aEntryOccurs > bEntryOccurs) return -1;
  112. if (aEntryOccurs < bEntryOccurs) return 1;
  113. const aOccurs = a.getNumberOfGroups();
  114. const bOccurs = b.getNumberOfGroups();
  115. if (aOccurs > bOccurs) return -1;
  116. if (aOccurs < bOccurs) return 1;
  117. const orgA = originalOrder.get(a);
  118. const orgB = originalOrder.get(b);
  119. return orgA - orgB;
  120. });
  121. }
  122. );
  123. });
  124. }
  125. }
  126. module.exports = OccurrenceOrderPlugin;