啊鑫
7 天以前 fca192d3c38c5dcfbb6ace8bc71d6078f6a079b2
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/*
    MIT License http://www.opensource.org/licenses/mit-license.php
    Author Tobias Koppers @sokra
*/
 
"use strict";
 
const { STAGE_BASIC } = require("../OptimizationStages");
const createSchemaValidation = require("../util/create-schema-validation");
const { runtimeEqual } = require("../util/runtime");
 
/** @typedef {import("../../declarations/plugins/optimize/MergeDuplicateChunksPlugin").MergeDuplicateChunksPluginOptions} MergeDuplicateChunksPluginOptions */
/** @typedef {import("../Compiler")} Compiler */
 
const validate = createSchemaValidation(
    require("../../schemas/plugins/optimize/MergeDuplicateChunksPlugin.check.js"),
    () =>
        require("../../schemas/plugins/optimize/MergeDuplicateChunksPlugin.json"),
    {
        name: "Merge Duplicate Chunks Plugin",
        baseDataPath: "options"
    }
);
 
class MergeDuplicateChunksPlugin {
    /**
     * @param {MergeDuplicateChunksPluginOptions} options options object
     */
    constructor(options = { stage: STAGE_BASIC }) {
        validate(options);
        this.options = options;
    }
 
    /**
     * @param {Compiler} compiler the compiler
     * @returns {void}
     */
    apply(compiler) {
        compiler.hooks.compilation.tap(
            "MergeDuplicateChunksPlugin",
            compilation => {
                compilation.hooks.optimizeChunks.tap(
                    {
                        name: "MergeDuplicateChunksPlugin",
                        stage: this.options.stage
                    },
                    chunks => {
                        const { chunkGraph, moduleGraph } = compilation;
 
                        // remember already tested chunks for performance
                        const notDuplicates = new Set();
 
                        // for each chunk
                        for (const chunk of chunks) {
                            // track a Set of all chunk that could be duplicates
                            let possibleDuplicates;
                            for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
                                if (possibleDuplicates === undefined) {
                                    // when possibleDuplicates is not yet set,
                                    // create a new Set from chunks of the current module
                                    // including only chunks with the same number of modules
                                    for (const dup of chunkGraph.getModuleChunksIterable(
                                        module
                                    )) {
                                        if (
                                            dup !== chunk &&
                                            chunkGraph.getNumberOfChunkModules(chunk) ===
                                                chunkGraph.getNumberOfChunkModules(dup) &&
                                            !notDuplicates.has(dup)
                                        ) {
                                            // delay allocating the new Set until here, reduce memory pressure
                                            if (possibleDuplicates === undefined) {
                                                possibleDuplicates = new Set();
                                            }
                                            possibleDuplicates.add(dup);
                                        }
                                    }
                                    // when no chunk is possible we can break here
                                    if (possibleDuplicates === undefined) break;
                                } else {
                                    // validate existing possible duplicates
                                    for (const dup of possibleDuplicates) {
                                        // remove possible duplicate when module is not contained
                                        if (!chunkGraph.isModuleInChunk(module, dup)) {
                                            possibleDuplicates.delete(dup);
                                        }
                                    }
                                    // when all chunks has been removed we can break here
                                    if (possibleDuplicates.size === 0) break;
                                }
                            }
 
                            // when we found duplicates
                            if (
                                possibleDuplicates !== undefined &&
                                possibleDuplicates.size > 0
                            ) {
                                outer: for (const otherChunk of possibleDuplicates) {
                                    if (otherChunk.hasRuntime() !== chunk.hasRuntime()) continue;
                                    if (chunkGraph.getNumberOfEntryModules(chunk) > 0) continue;
                                    if (chunkGraph.getNumberOfEntryModules(otherChunk) > 0)
                                        continue;
                                    if (!runtimeEqual(chunk.runtime, otherChunk.runtime)) {
                                        for (const module of chunkGraph.getChunkModulesIterable(
                                            chunk
                                        )) {
                                            const exportsInfo = moduleGraph.getExportsInfo(module);
                                            if (
                                                !exportsInfo.isEquallyUsed(
                                                    chunk.runtime,
                                                    otherChunk.runtime
                                                )
                                            ) {
                                                continue outer;
                                            }
                                        }
                                    }
                                    // merge them
                                    if (chunkGraph.canChunksBeIntegrated(chunk, otherChunk)) {
                                        chunkGraph.integrateChunks(chunk, otherChunk);
                                        compilation.chunks.delete(otherChunk);
                                    }
                                }
                            }
 
                            // don't check already processed chunks twice
                            notDuplicates.add(chunk);
                        }
                    }
                );
            }
        );
    }
}
module.exports = MergeDuplicateChunksPlugin;