MinChunkSizePlugin.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  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"),
  13. () => require("../../schemas/plugins/optimize/MinChunkSizePlugin.json"),
  14. {
  15. name: "Min Chunk Size Plugin",
  16. baseDataPath: "options"
  17. }
  18. );
  19. const PLUGIN_NAME = "MinChunkSizePlugin";
  20. class MinChunkSizePlugin {
  21. /**
  22. * @param {MinChunkSizePluginOptions} options options object
  23. */
  24. constructor(options) {
  25. validate(options);
  26. /** @type {MinChunkSizePluginOptions} */
  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 minChunkSize = options.minChunkSize;
  37. compiler.hooks.compilation.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. const equalOptions = {
  46. chunkOverhead: 1,
  47. entryChunkMultiplicator: 1
  48. };
  49. /** @type {Map<Chunk, number>} */
  50. const chunkSizesMap = new Map();
  51. /** @type {[Chunk, Chunk][]} */
  52. const combinations = [];
  53. /** @type {Chunk[]} */
  54. const smallChunks = [];
  55. /** @type {Chunk[]} */
  56. const visitedChunks = [];
  57. for (const a of chunks) {
  58. // check if one of the chunks sizes is smaller than the minChunkSize
  59. // and filter pairs that can NOT be integrated!
  60. if (chunkGraph.getChunkSize(a, equalOptions) < minChunkSize) {
  61. smallChunks.push(a);
  62. for (const b of visitedChunks) {
  63. if (chunkGraph.canChunksBeIntegrated(b, a)) {
  64. combinations.push([b, a]);
  65. }
  66. }
  67. } else {
  68. for (const b of smallChunks) {
  69. if (chunkGraph.canChunksBeIntegrated(b, a)) {
  70. combinations.push([b, a]);
  71. }
  72. }
  73. }
  74. chunkSizesMap.set(a, chunkGraph.getChunkSize(a, options));
  75. visitedChunks.push(a);
  76. }
  77. const sortedSizeFilteredExtendedPairCombinations = combinations
  78. .map((pair) => {
  79. // extend combination pairs with size and integrated size
  80. const a = /** @type {number} */ (chunkSizesMap.get(pair[0]));
  81. const b = /** @type {number} */ (chunkSizesMap.get(pair[1]));
  82. const ab = chunkGraph.getIntegratedChunksSize(
  83. pair[0],
  84. pair[1],
  85. options
  86. );
  87. /** @type {[number, number, Chunk, Chunk]} */
  88. const extendedPair = [a + b - ab, ab, pair[0], pair[1]];
  89. return extendedPair;
  90. })
  91. .sort((a, b) => {
  92. // sadly javascript does an in place sort here
  93. // sort by size
  94. const diff = b[0] - a[0];
  95. if (diff !== 0) return diff;
  96. return a[1] - b[1];
  97. });
  98. if (sortedSizeFilteredExtendedPairCombinations.length === 0) return;
  99. const pair = sortedSizeFilteredExtendedPairCombinations[0];
  100. chunkGraph.integrateChunks(pair[2], pair[3]);
  101. compilation.chunks.delete(pair[3]);
  102. return true;
  103. }
  104. );
  105. });
  106. }
  107. }
  108. module.exports = MinChunkSizePlugin;