source: frontend/node_modules/webpack/lib/optimize/FlagIncludedChunksPlugin.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 11 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 4.3 KB
Line 
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6"use strict";
7
8const { compareIds } = require("../util/comparators");
9
10/** @typedef {import("../Chunk")} Chunk */
11/** @typedef {import("../Chunk").ChunkId} ChunkId */
12/** @typedef {import("../Compiler")} Compiler */
13/** @typedef {import("../Module")} Module */
14
15const PLUGIN_NAME = "FlagIncludedChunksPlugin";
16
17class FlagIncludedChunksPlugin {
18 /**
19 * Applies the plugin by registering its hooks on the compiler.
20 * @param {Compiler} compiler the compiler instance
21 * @returns {void}
22 */
23 apply(compiler) {
24 compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
25 compilation.hooks.optimizeChunkIds.tap(PLUGIN_NAME, (chunks) => {
26 const chunkGraph = compilation.chunkGraph;
27
28 // prepare two bit integers for each module
29 // 2^31 is the max number represented as SMI in v8
30 // we want the bits distributed this way:
31 // the bit 2^31 is pretty rar and only one module should get it
32 // so it has a probability of 1 / modulesCount
33 // the first bit (2^0) is the easiest and every module could get it
34 // if it doesn't get a better bit
35 // from bit 2^n to 2^(n+1) there is a probability of p
36 // so 1 / modulesCount == p^31
37 // <=> p = sqrt31(1 / modulesCount)
38 // so we use a modulo of 1 / sqrt31(1 / modulesCount)
39 /** @type {WeakMap<Module, number>} */
40 const moduleBits = new WeakMap();
41 const modulesCount = compilation.modules.size;
42
43 // precalculate the modulo values for each bit
44 const modulo = 1 / (1 / modulesCount) ** (1 / 31);
45 /** @type {number[]} */
46 const modulos = Array.from(
47 { length: 31 },
48 /**
49 * Handles the callback logic for this hook.
50 * @param {number} x x
51 * @param {number} i i
52 * @returns {number} result
53 */
54 (x, i) => (modulo ** i) | 0
55 );
56
57 // iterate all modules to generate bit values
58 let i = 0;
59 for (const module of compilation.modules) {
60 let bit = 30;
61 while (i % modulos[bit] !== 0) {
62 bit--;
63 }
64 moduleBits.set(module, 1 << bit);
65 i++;
66 }
67
68 // iterate all chunks to generate bitmaps
69 /** @type {WeakMap<Chunk, number>} */
70 const chunkModulesHash = new WeakMap();
71 for (const chunk of chunks) {
72 let hash = 0;
73 for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
74 hash |= /** @type {number} */ (moduleBits.get(module));
75 }
76 chunkModulesHash.set(chunk, hash);
77 }
78
79 for (const chunkA of chunks) {
80 const chunkAHash =
81 /** @type {number} */
82 (chunkModulesHash.get(chunkA));
83 const chunkAModulesCount = chunkGraph.getNumberOfChunkModules(chunkA);
84 if (chunkAModulesCount === 0) continue;
85 /** @type {undefined | Module} */
86 let bestModule;
87 for (const module of chunkGraph.getChunkModulesIterable(chunkA)) {
88 if (
89 bestModule === undefined ||
90 chunkGraph.getNumberOfModuleChunks(bestModule) >
91 chunkGraph.getNumberOfModuleChunks(module)
92 ) {
93 bestModule = module;
94 }
95 }
96 loopB: for (const chunkB of chunkGraph.getModuleChunksIterable(
97 /** @type {Module} */ (bestModule)
98 )) {
99 // as we iterate the same iterables twice
100 // skip if we find ourselves
101 if (chunkA === chunkB) continue;
102
103 const chunkBModulesCount =
104 chunkGraph.getNumberOfChunkModules(chunkB);
105
106 // ids for empty chunks are not included
107 if (chunkBModulesCount === 0) continue;
108
109 // instead of swapping A and B just bail
110 // as we loop twice the current A will be B and B then A
111 if (chunkAModulesCount > chunkBModulesCount) continue;
112
113 // is chunkA in chunkB?
114
115 // we do a cheap check for the hash value
116 const chunkBHash =
117 /** @type {number} */
118 (chunkModulesHash.get(chunkB));
119 if ((chunkBHash & chunkAHash) !== chunkAHash) continue;
120
121 // compare all modules
122 for (const m of chunkGraph.getChunkModulesIterable(chunkA)) {
123 if (!chunkGraph.isModuleInChunk(m, chunkB)) continue loopB;
124 }
125
126 /** @type {ChunkId[]} */
127 (chunkB.ids).push(/** @type {ChunkId} */ (chunkA.id));
128 // https://github.com/webpack/webpack/issues/18837
129 /** @type {ChunkId[]} */
130 (chunkB.ids).sort(compareIds);
131 }
132 }
133 });
134 });
135 }
136}
137
138module.exports = FlagIncludedChunksPlugin;
Note: See TracBrowser for help on using the repository browser.