AggressiveMergingPlugin.js 2.4 KB

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