123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 |
- "use strict";
- const validateOptions = require("schema-utils");
- const schema = require("../../schemas/plugins/optimize/LimitChunkCountPlugin.json");
- const LazyBucketSortedSet = require("../util/LazyBucketSortedSet");
- const addToSetMap = (map, key, value) => {
- const set = map.get(key);
- if (set === undefined) {
- map.set(key, new Set([value]));
- } else {
- set.add(value);
- }
- };
- class LimitChunkCountPlugin {
-
- constructor(options) {
- if (!options) options = {};
- validateOptions(schema, options, "Limit Chunk Count Plugin");
- this.options = options;
- }
-
- apply(compiler) {
- const options = this.options;
- compiler.hooks.compilation.tap("LimitChunkCountPlugin", compilation => {
- compilation.hooks.optimizeChunksAdvanced.tap(
- "LimitChunkCountPlugin",
- chunks => {
- const maxChunks = options.maxChunks;
- if (!maxChunks) return;
- if (maxChunks < 1) return;
- if (chunks.length <= maxChunks) return;
- let remainingChunksToMerge = chunks.length - maxChunks;
-
- const orderedChunks = chunks.slice().sort((a, b) => a.compareTo(b));
-
-
-
-
- const combinations = new LazyBucketSortedSet(
-
- c => c.sizeDiff,
- (a, b) => b - a,
-
- c => c.integratedSize,
- (a, b) => a - b,
-
- c => c.bIdx - c.aIdx,
- (a, b) => a - b,
-
- (a, b) => a.bIdx - b.bIdx
- );
-
-
-
-
- const combinationsByChunk = new Map();
- orderedChunks.forEach((b, bIdx) => {
-
- for (let aIdx = 0; aIdx < bIdx; aIdx++) {
- const a = orderedChunks[aIdx];
- const integratedSize = a.integratedSize(b, options);
-
-
- if (integratedSize === false) continue;
- const aSize = a.size(options);
- const bSize = b.size(options);
- const c = {
- deleted: false,
- sizeDiff: aSize + bSize - integratedSize,
- integratedSize,
- a,
- b,
- aIdx,
- bIdx,
- aSize,
- bSize
- };
- combinations.add(c);
- addToSetMap(combinationsByChunk, a, c);
- addToSetMap(combinationsByChunk, b, c);
- }
- return combinations;
- });
-
-
-
-
- const modifiedChunks = new Set();
- let changed = false;
-
- loop: while (true) {
- const combination = combinations.popFirst();
- if (combination === undefined) break;
- combination.deleted = true;
- const { a, b, integratedSize } = combination;
-
-
- if (modifiedChunks.size > 0) {
- const queue = new Set(a.groupsIterable);
- for (const group of b.groupsIterable) {
- queue.add(group);
- }
- for (const group of queue) {
- for (const mChunk of modifiedChunks) {
- if (mChunk !== a && mChunk !== b && mChunk.isInGroup(group)) {
-
-
-
-
- remainingChunksToMerge--;
- if (remainingChunksToMerge <= 0) break loop;
- modifiedChunks.add(a);
- modifiedChunks.add(b);
- continue loop;
- }
- }
- for (const parent of group.parentsIterable) {
- queue.add(parent);
- }
- }
- }
-
- if (a.integrate(b, "limit")) {
- chunks.splice(chunks.indexOf(b), 1);
-
- modifiedChunks.add(a);
- changed = true;
- remainingChunksToMerge--;
- if (remainingChunksToMerge <= 0) break;
-
-
-
- for (const combination of combinationsByChunk.get(b)) {
- if (combination.deleted) continue;
- combination.deleted = true;
- combinations.delete(combination);
- }
-
- for (const combination of combinationsByChunk.get(a)) {
- if (combination.deleted) continue;
- if (combination.a === a) {
-
- const newIntegratedSize = a.integratedSize(
- combination.b,
- options
- );
- if (newIntegratedSize === false) {
- combination.deleted = true;
- combinations.delete(combination);
- continue;
- }
- const finishUpdate = combinations.startUpdate(combination);
- combination.integratedSize = newIntegratedSize;
- combination.aSize = integratedSize;
- combination.sizeDiff =
- combination.bSize + integratedSize - newIntegratedSize;
- finishUpdate();
- } else if (combination.b === a) {
-
- const newIntegratedSize = combination.a.integratedSize(
- a,
- options
- );
- if (newIntegratedSize === false) {
- combination.deleted = true;
- combinations.delete(combination);
- continue;
- }
- const finishUpdate = combinations.startUpdate(combination);
- combination.integratedSize = newIntegratedSize;
- combination.bSize = integratedSize;
- combination.sizeDiff =
- integratedSize + combination.aSize - newIntegratedSize;
- finishUpdate();
- }
- }
- }
- }
- if (changed) return true;
- }
- );
- });
- }
- }
- module.exports = LimitChunkCountPlugin;
|