AggressiveMergingPlugin.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. class AggressiveMergingPlugin {
  7. constructor(options) {
  8. if(options !== undefined && typeof options !== "object" || Array.isArray(options)) {
  9. throw new Error("Argument should be an options object. To use defaults, pass in nothing.\nFor more info on options, see https://webpack.js.org/plugins/");
  10. }
  11. this.options = options || {};
  12. }
  13. apply(compiler) {
  14. const options = this.options;
  15. const minSizeReduce = options.minSizeReduce || 1.5;
  16. function getParentsWeight(chunk) {
  17. return chunk.parents.map((p) => {
  18. return p.isInitial() ? options.entryChunkMultiplicator || 10 : 1;
  19. }).reduce((a, b) => {
  20. return a + b;
  21. }, 0);
  22. }
  23. compiler.plugin("this-compilation", (compilation) => {
  24. compilation.plugin("optimize-chunks-advanced", (chunks) => {
  25. let combinations = [];
  26. chunks.forEach((a, idx) => {
  27. if(a.isInitial()) return;
  28. for(let i = 0; i < idx; i++) {
  29. const b = chunks[i];
  30. if(b.isInitial()) continue;
  31. combinations.push({
  32. a,
  33. b,
  34. improvement: undefined
  35. });
  36. }
  37. });
  38. combinations.forEach((pair) => {
  39. const a = pair.b.size({
  40. chunkOverhead: 0
  41. });
  42. const b = pair.a.size({
  43. chunkOverhead: 0
  44. });
  45. const ab = pair.b.integratedSize(pair.a, {
  46. chunkOverhead: 0
  47. });
  48. let newSize;
  49. if(ab === false) {
  50. pair.improvement = false;
  51. return;
  52. } else if(options.moveToParents) {
  53. const aOnly = ab - b;
  54. const bOnly = ab - a;
  55. const common = a + b - ab;
  56. newSize = common + getParentsWeight(pair.b) * aOnly + getParentsWeight(pair.a) * bOnly;
  57. } else {
  58. newSize = ab;
  59. }
  60. pair.improvement = (a + b) / newSize;
  61. });
  62. combinations = combinations.filter((pair) => {
  63. return pair.improvement !== false;
  64. });
  65. combinations.sort((a, b) => {
  66. return b.improvement - a.improvement;
  67. });
  68. const pair = combinations[0];
  69. if(!pair) return;
  70. if(pair.improvement < minSizeReduce) return;
  71. if(options.moveToParents) {
  72. const commonModules = pair.b.modules.filter((m) => {
  73. return pair.a.modules.indexOf(m) >= 0;
  74. });
  75. const aOnlyModules = pair.b.modules.filter((m) => {
  76. return commonModules.indexOf(m) < 0;
  77. });
  78. const bOnlyModules = pair.a.modules.filter((m) => {
  79. return commonModules.indexOf(m) < 0;
  80. });
  81. aOnlyModules.forEach((m) => {
  82. pair.b.removeModule(m);
  83. m.removeChunk(pair.b);
  84. pair.b.parents.forEach((c) => {
  85. c.addModule(m);
  86. m.addChunk(c);
  87. });
  88. });
  89. bOnlyModules.forEach((m) => {
  90. pair.a.removeModule(m);
  91. m.removeChunk(pair.a);
  92. pair.a.parents.forEach((c) => {
  93. c.addModule(m);
  94. m.addChunk(c);
  95. });
  96. });
  97. }
  98. if(pair.b.integrate(pair.a, "aggressive-merge")) {
  99. chunks.splice(chunks.indexOf(pair.a), 1);
  100. return true;
  101. }
  102. });
  103. });
  104. }
  105. }
  106. module.exports = AggressiveMergingPlugin;