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