OccurrenceOrderPlugin.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. class OccurrenceOrderPlugin {
  7. constructor(preferEntry) {
  8. if(preferEntry !== undefined && typeof preferEntry !== "boolean") {
  9. throw new Error("Argument should be a boolean.\nFor more info on this plugin, see https://webpack.js.org/plugins/");
  10. }
  11. this.preferEntry = preferEntry;
  12. }
  13. apply(compiler) {
  14. const preferEntry = this.preferEntry;
  15. compiler.plugin("compilation", (compilation) => {
  16. compilation.plugin("optimize-module-order", (modules) => {
  17. function entryChunks(m) {
  18. return m.chunks.map((c) => {
  19. const sum = (c.isInitial() ? 1 : 0) + (c.entryModule === m ? 1 : 0);
  20. return sum;
  21. }).reduce((a, b) => {
  22. return a + b;
  23. }, 0);
  24. }
  25. function occursInEntry(m) {
  26. if(typeof m.__OccurenceOrderPlugin_occursInEntry === "number") return m.__OccurenceOrderPlugin_occursInEntry;
  27. const result = m.reasons.map((r) => {
  28. if(!r.module) return 0;
  29. return entryChunks(r.module);
  30. }).reduce((a, b) => {
  31. return a + b;
  32. }, 0) + entryChunks(m);
  33. return m.__OccurenceOrderPlugin_occursInEntry = result;
  34. }
  35. function occurs(m) {
  36. if(typeof m.__OccurenceOrderPlugin_occurs === "number") return m.__OccurenceOrderPlugin_occurs;
  37. const result = m.reasons.map((r) => {
  38. if(!r.module) return 0;
  39. return r.module.chunks.length;
  40. }).reduce((a, b) => {
  41. return a + b;
  42. }, 0) + m.chunks.length + m.chunks.filter((c) => {
  43. return c.entryModule === m;
  44. }).length;
  45. return m.__OccurenceOrderPlugin_occurs = result;
  46. }
  47. modules.sort((a, b) => {
  48. if(preferEntry) {
  49. const aEntryOccurs = occursInEntry(a);
  50. const bEntryOccurs = occursInEntry(b);
  51. if(aEntryOccurs > bEntryOccurs) return -1;
  52. if(aEntryOccurs < bEntryOccurs) return 1;
  53. }
  54. const aOccurs = occurs(a);
  55. const bOccurs = occurs(b);
  56. if(aOccurs > bOccurs) return -1;
  57. if(aOccurs < bOccurs) return 1;
  58. if(a.identifier() > b.identifier()) return 1;
  59. if(a.identifier() < b.identifier()) return -1;
  60. return 0;
  61. });
  62. // TODO refactor to Map
  63. modules.forEach((m) => {
  64. m.__OccurenceOrderPlugin_occursInEntry = undefined;
  65. m.__OccurenceOrderPlugin_occurs = undefined;
  66. });
  67. });
  68. compilation.plugin("optimize-chunk-order", (chunks) => {
  69. function occursInEntry(c) {
  70. if(typeof c.__OccurenceOrderPlugin_occursInEntry === "number") return c.__OccurenceOrderPlugin_occursInEntry;
  71. const result = c.parents.filter((p) => {
  72. return p.isInitial();
  73. }).length;
  74. return c.__OccurenceOrderPlugin_occursInEntry = result;
  75. }
  76. function occurs(c) {
  77. return c.blocks.length;
  78. }
  79. chunks.forEach((c) => {
  80. c.modules.sort((a, b) => {
  81. if(a.identifier() > b.identifier()) return 1;
  82. if(a.identifier() < b.identifier()) return -1;
  83. return 0;
  84. });
  85. });
  86. chunks.sort((a, b) => {
  87. const aEntryOccurs = occursInEntry(a);
  88. const bEntryOccurs = occursInEntry(b);
  89. if(aEntryOccurs > bEntryOccurs) return -1;
  90. if(aEntryOccurs < bEntryOccurs) return 1;
  91. const aOccurs = occurs(a);
  92. const bOccurs = occurs(b);
  93. if(aOccurs > bOccurs) return -1;
  94. if(aOccurs < bOccurs) return 1;
  95. if(a.modules.length > b.modules.length) return -1;
  96. if(a.modules.length < b.modules.length) return 1;
  97. for(let i = 0; i < a.modules.length; i++) {
  98. if(a.modules[i].identifier() > b.modules[i].identifier()) return -1;
  99. if(a.modules[i].identifier() < b.modules[i].identifier()) return 1;
  100. }
  101. return 0;
  102. });
  103. // TODO refactor to Map
  104. chunks.forEach((c) => {
  105. c.__OccurenceOrderPlugin_occursInEntry = undefined;
  106. });
  107. });
  108. });
  109. }
  110. }
  111. module.exports = OccurrenceOrderPlugin;