File: OccurrenceModuleOrderPlugin.js

package info (click to toggle)
node-webpack 4.43.0-6%2Bdeb11u1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 21,308 kB
  • sloc: javascript: 70,001; makefile: 22
file content (112 lines) | stat: -rw-r--r-- 3,345 bytes parent folder | download
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
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/
"use strict";

const validateOptions = require("schema-utils").validate;
const schema = require("../../schemas/plugins/optimize/OccurrenceOrderModuleIdsPlugin.json");

/** @typedef {import("../../declarations/plugins/optimize/OccurrenceOrderModuleIdsPlugin").OccurrenceOrderModuleIdsPluginOptions} OccurrenceOrderModuleIdsPluginOptions */

class OccurrenceOrderModuleIdsPlugin {
	/**
	 * @param {OccurrenceOrderModuleIdsPluginOptions=} options options object
	 */
	constructor(options = {}) {
		validateOptions(schema, options, "Occurrence Order Module Ids Plugin");
		this.options = options;
	}

	apply(compiler) {
		const prioritiseInitial = this.options.prioritiseInitial;
		compiler.hooks.compilation.tap(
			"OccurrenceOrderModuleIdsPlugin",
			compilation => {
				compilation.hooks.optimizeModuleOrder.tap(
					"OccurrenceOrderModuleIdsPlugin",
					modules => {
						const occursInInitialChunksMap = new Map();
						const occursInAllChunksMap = new Map();

						const initialChunkChunkMap = new Map();
						const entryCountMap = new Map();
						for (const m of modules) {
							let initial = 0;
							let entry = 0;
							for (const c of m.chunksIterable) {
								if (c.canBeInitial()) initial++;
								if (c.entryModule === m) entry++;
							}
							initialChunkChunkMap.set(m, initial);
							entryCountMap.set(m, entry);
						}

						const countOccursInEntry = (sum, r) => {
							if (!r.module) {
								return sum;
							}
							const count = initialChunkChunkMap.get(r.module);
							if (!count) {
								return sum;
							}
							return sum + count;
						};
						const countOccurs = (sum, r) => {
							if (!r.module) {
								return sum;
							}
							let factor = 1;
							if (typeof r.dependency.getNumberOfIdOccurrences === "function") {
								factor = r.dependency.getNumberOfIdOccurrences();
							}
							if (factor === 0) {
								return sum;
							}
							return sum + factor * r.module.getNumberOfChunks();
						};

						if (prioritiseInitial) {
							for (const m of modules) {
								const result =
									m.reasons.reduce(countOccursInEntry, 0) +
									initialChunkChunkMap.get(m) +
									entryCountMap.get(m);
								occursInInitialChunksMap.set(m, result);
							}
						}

						const originalOrder = new Map();
						let i = 0;
						for (const m of modules) {
							const result =
								m.reasons.reduce(countOccurs, 0) +
								m.getNumberOfChunks() +
								entryCountMap.get(m);
							occursInAllChunksMap.set(m, result);
							originalOrder.set(m, i++);
						}

						modules.sort((a, b) => {
							if (prioritiseInitial) {
								const aEntryOccurs = occursInInitialChunksMap.get(a);
								const bEntryOccurs = occursInInitialChunksMap.get(b);
								if (aEntryOccurs > bEntryOccurs) return -1;
								if (aEntryOccurs < bEntryOccurs) return 1;
							}
							const aOccurs = occursInAllChunksMap.get(a);
							const bOccurs = occursInAllChunksMap.get(b);
							if (aOccurs > bOccurs) return -1;
							if (aOccurs < bOccurs) return 1;
							const orgA = originalOrder.get(a);
							const orgB = originalOrder.get(b);
							return orgA - orgB;
						});
					}
				);
			}
		);
	}
}

module.exports = OccurrenceOrderModuleIdsPlugin;