MinChunkSizePlugin.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  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. const createSchemaValidation = require("../util/create-schema-validation");
  8. /** @typedef {import("../../declarations/plugins/optimize/MinChunkSizePlugin").MinChunkSizePluginOptions} MinChunkSizePluginOptions */
  9. /** @typedef {import("../Chunk")} Chunk */
  10. /** @typedef {import("../Compiler")} Compiler */
  11. const validate = createSchemaValidation(
  12. require("../../schemas/plugins/optimize/MinChunkSizePlugin.check.js"),
  13. () => require("../../schemas/plugins/optimize/MinChunkSizePlugin.json"),
  14. {
  15. name: "Min Chunk Size Plugin",
  16. baseDataPath: "options"
  17. }
  18. );
  19. class MinChunkSizePlugin {
  20. /**
  21. * @param {MinChunkSizePluginOptions} options options object
  22. */
  23. constructor(options) {
  24. validate(options);
  25. this.options = options;
  26. }
  27. /**
  28. * Apply the plugin
  29. * @param {Compiler} compiler the compiler instance
  30. * @returns {void}
  31. */
  32. apply(compiler) {
  33. const options = this.options;
  34. const minChunkSize = options.minChunkSize;
  35. compiler.hooks.compilation.tap("MinChunkSizePlugin", compilation => {
  36. compilation.hooks.optimizeChunks.tap(
  37. {
  38. name: "MinChunkSizePlugin",
  39. stage: STAGE_ADVANCED
  40. },
  41. chunks => {
  42. const chunkGraph = compilation.chunkGraph;
  43. const equalOptions = {
  44. chunkOverhead: 1,
  45. entryChunkMultiplicator: 1
  46. };
  47. const chunkSizesMap = new Map();
  48. /** @type {[Chunk, Chunk][]} */
  49. const combinations = [];
  50. /** @type {Chunk[]} */
  51. const smallChunks = [];
  52. const visitedChunks = [];
  53. for (const a of chunks) {
  54. // check if one of the chunks sizes is smaller than the minChunkSize
  55. // and filter pairs that can NOT be integrated!
  56. if (chunkGraph.getChunkSize(a, equalOptions) < minChunkSize) {
  57. smallChunks.push(a);
  58. for (const b of visitedChunks) {
  59. if (chunkGraph.canChunksBeIntegrated(b, a))
  60. combinations.push([b, a]);
  61. }
  62. } else {
  63. for (const b of smallChunks) {
  64. if (chunkGraph.canChunksBeIntegrated(b, a))
  65. combinations.push([b, a]);
  66. }
  67. }
  68. chunkSizesMap.set(a, chunkGraph.getChunkSize(a, options));
  69. visitedChunks.push(a);
  70. }
  71. const sortedSizeFilteredExtendedPairCombinations = combinations
  72. .map(pair => {
  73. // extend combination pairs with size and integrated size
  74. const a = chunkSizesMap.get(pair[0]);
  75. const b = chunkSizesMap.get(pair[1]);
  76. const ab = chunkGraph.getIntegratedChunksSize(
  77. pair[0],
  78. pair[1],
  79. options
  80. );
  81. /** @type {[number, number, Chunk, Chunk]} */
  82. const extendedPair = [a + b - ab, ab, pair[0], pair[1]];
  83. return extendedPair;
  84. })
  85. .sort((a, b) => {
  86. // sadly javascript does an in place sort here
  87. // sort by size
  88. const diff = b[0] - a[0];
  89. if (diff !== 0) return diff;
  90. return a[1] - b[1];
  91. });
  92. if (sortedSizeFilteredExtendedPairCombinations.length === 0) return;
  93. const pair = sortedSizeFilteredExtendedPairCombinations[0];
  94. chunkGraph.integrateChunks(pair[2], pair[3]);
  95. compilation.chunks.delete(pair[3]);
  96. return true;
  97. }
  98. );
  99. });
  100. }
  101. }
  102. module.exports = MinChunkSizePlugin;