AggressiveMergingPlugin.js 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const { STAGE_ADVANCED } = require("../OptimizationStages");
  7. /** @typedef {import("../Chunk")} Chunk */
  8. /** @typedef {import("../Compiler")} Compiler */
  9. /**
  10. * @typedef {object} AggressiveMergingPluginOptions
  11. * @property {number=} minSizeReduce minimal size reduction to trigger merging
  12. */
  13. class AggressiveMergingPlugin {
  14. /**
  15. * @param {AggressiveMergingPluginOptions=} [options] options object
  16. */
  17. constructor(options) {
  18. if (
  19. (options !== undefined && typeof options !== "object") ||
  20. Array.isArray(options)
  21. ) {
  22. throw new Error(
  23. "Argument should be an options object. To use defaults, pass in nothing.\nFor more info on options, see https://webpack.js.org/plugins/"
  24. );
  25. }
  26. this.options = options || {};
  27. }
  28. /**
  29. * Apply the plugin
  30. * @param {Compiler} compiler the compiler instance
  31. * @returns {void}
  32. */
  33. apply(compiler) {
  34. const options = this.options;
  35. const minSizeReduce = options.minSizeReduce || 1.5;
  36. compiler.hooks.thisCompilation.tap(
  37. "AggressiveMergingPlugin",
  38. compilation => {
  39. compilation.hooks.optimizeChunks.tap(
  40. {
  41. name: "AggressiveMergingPlugin",
  42. stage: STAGE_ADVANCED
  43. },
  44. chunks => {
  45. const chunkGraph = compilation.chunkGraph;
  46. /** @type {{a: Chunk, b: Chunk, improvement: number}[]} */
  47. const combinations = [];
  48. for (const a of chunks) {
  49. if (a.canBeInitial()) continue;
  50. for (const b of chunks) {
  51. if (b.canBeInitial()) continue;
  52. if (b === a) break;
  53. if (!chunkGraph.canChunksBeIntegrated(a, b)) {
  54. continue;
  55. }
  56. const aSize = chunkGraph.getChunkSize(b, {
  57. chunkOverhead: 0
  58. });
  59. const bSize = chunkGraph.getChunkSize(a, {
  60. chunkOverhead: 0
  61. });
  62. const abSize = chunkGraph.getIntegratedChunksSize(b, a, {
  63. chunkOverhead: 0
  64. });
  65. const improvement = (aSize + bSize) / abSize;
  66. combinations.push({
  67. a,
  68. b,
  69. improvement
  70. });
  71. }
  72. }
  73. combinations.sort((a, b) => b.improvement - a.improvement);
  74. const pair = combinations[0];
  75. if (!pair) return;
  76. if (pair.improvement < minSizeReduce) return;
  77. chunkGraph.integrateChunks(pair.b, pair.a);
  78. compilation.chunks.delete(pair.a);
  79. return true;
  80. }
  81. );
  82. }
  83. );
  84. }
  85. }
  86. module.exports = AggressiveMergingPlugin;