webpack 5.22.0 → 5.24.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of webpack might be problematic. Click here for more details.
- package/bin/webpack.js +0 -0
- package/lib/CaseSensitiveModulesWarning.js +3 -3
- package/lib/ChunkGraph.js +13 -5
- package/lib/Compilation.js +14 -7
- package/lib/Dependency.js +2 -0
- package/lib/ExportsInfo.js +23 -7
- package/lib/FlagDependencyExportsPlugin.js +16 -5
- package/lib/Module.js +5 -3
- package/lib/ModuleGraph.js +42 -6
- package/lib/ModuleGraphConnection.js +2 -2
- package/lib/MultiCompiler.js +29 -12
- package/lib/RuntimeGlobals.js +5 -0
- package/lib/RuntimePlugin.js +8 -0
- package/lib/Watching.js +13 -18
- package/lib/WebpackOptionsApply.js +6 -6
- package/lib/async-modules/InferAsyncModulesPlugin.js +10 -6
- package/lib/config/defaults.js +26 -10
- package/lib/config/target.js +1 -1
- package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +60 -20
- package/lib/dependencies/URLDependency.js +35 -13
- package/lib/dependencies/URLPlugin.js +3 -1
- package/lib/dependencies/WorkerPlugin.js +7 -1
- package/lib/ids/OccurrenceModuleIdsPlugin.js +28 -17
- package/lib/index.js +2 -0
- package/lib/javascript/CommonJsChunkFormatPlugin.js +15 -4
- package/lib/javascript/JavascriptModulesPlugin.js +5 -5
- package/lib/node/NodeTargetPlugin.js +1 -1
- package/lib/node/NodeWatchFileSystem.js +6 -0
- package/lib/optimize/ConcatenatedModule.js +14 -9
- package/lib/optimize/ModuleConcatenationPlugin.js +559 -516
- package/lib/optimize/SideEffectsFlagPlugin.js +17 -1
- package/lib/runtime/RelativeUrlRuntimeModule.js +41 -0
- package/lib/runtime/StartupChunkDependenciesPlugin.js +1 -0
- package/lib/stats/DefaultStatsFactoryPlugin.js +140 -131
- package/lib/util/SetHelpers.js +15 -0
- package/lib/util/fs.js +2 -0
- package/lib/util/semver.js +4 -4
- package/package.json +3 -8
- package/schemas/WebpackOptions.json +147 -5
- package/types.d.ts +122 -23
@@ -8,11 +8,8 @@
|
|
8
8
|
const asyncLib = require("neo-async");
|
9
9
|
const ChunkGraph = require("../ChunkGraph");
|
10
10
|
const ModuleGraph = require("../ModuleGraph");
|
11
|
-
const ModuleRestoreError = require("../ModuleRestoreError");
|
12
|
-
const ModuleStoreError = require("../ModuleStoreError");
|
13
11
|
const { STAGE_DEFAULT } = require("../OptimizationStages");
|
14
12
|
const HarmonyImportDependency = require("../dependencies/HarmonyImportDependency");
|
15
|
-
const StackedMap = require("../util/StackedMap");
|
16
13
|
const { compareModulesByIdentifier } = require("../util/comparators");
|
17
14
|
const {
|
18
15
|
intersectRuntime,
|
@@ -29,6 +26,20 @@ const ConcatenatedModule = require("./ConcatenatedModule");
|
|
29
26
|
/** @typedef {import("../RequestShortener")} RequestShortener */
|
30
27
|
/** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */
|
31
28
|
|
29
|
+
/**
|
30
|
+
* @typedef {Object} Statistics
|
31
|
+
* @property {number} cached
|
32
|
+
* @property {number} alreadyInConfig
|
33
|
+
* @property {number} invalidModule
|
34
|
+
* @property {number} incorrectChunks
|
35
|
+
* @property {number} incorrectDependency
|
36
|
+
* @property {number} incorrectModuleDependency
|
37
|
+
* @property {number} incorrectChunksOfImporter
|
38
|
+
* @property {number} incorrectRuntimeCondition
|
39
|
+
* @property {number} importerFailed
|
40
|
+
* @property {number} added
|
41
|
+
*/
|
42
|
+
|
32
43
|
const formatBailoutReason = msg => {
|
33
44
|
return "ModuleConcatenation bailout: " + msg;
|
34
45
|
};
|
@@ -45,414 +56,404 @@ class ModuleConcatenationPlugin {
|
|
45
56
|
* @returns {void}
|
46
57
|
*/
|
47
58
|
apply(compiler) {
|
48
|
-
compiler.hooks.compilation.tap(
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
: formatBailoutReason(reason)
|
63
|
-
);
|
64
|
-
};
|
65
|
-
|
66
|
-
const setInnerBailoutReason = (module, reason) => {
|
67
|
-
bailoutReasonMap.set(module, reason);
|
68
|
-
};
|
59
|
+
compiler.hooks.compilation.tap("ModuleConcatenationPlugin", compilation => {
|
60
|
+
const moduleGraph = compilation.moduleGraph;
|
61
|
+
const bailoutReasonMap = new Map();
|
62
|
+
|
63
|
+
const setBailoutReason = (module, reason) => {
|
64
|
+
setInnerBailoutReason(module, reason);
|
65
|
+
moduleGraph
|
66
|
+
.getOptimizationBailout(module)
|
67
|
+
.push(
|
68
|
+
typeof reason === "function"
|
69
|
+
? rs => formatBailoutReason(reason(rs))
|
70
|
+
: formatBailoutReason(reason)
|
71
|
+
);
|
72
|
+
};
|
69
73
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
return reason;
|
74
|
-
};
|
74
|
+
const setInnerBailoutReason = (module, reason) => {
|
75
|
+
bailoutReasonMap.set(module, reason);
|
76
|
+
};
|
75
77
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
)}: ${problem(requestShortener)}`
|
82
|
-
);
|
83
|
-
}
|
84
|
-
const reason = getInnerBailoutReason(module, requestShortener);
|
85
|
-
const reasonWithPrefix = reason ? `: ${reason}` : "";
|
86
|
-
if (module === problem) {
|
87
|
-
return formatBailoutReason(
|
88
|
-
`Cannot concat with ${module.readableIdentifier(
|
89
|
-
requestShortener
|
90
|
-
)}${reasonWithPrefix}`
|
91
|
-
);
|
92
|
-
} else {
|
93
|
-
return formatBailoutReason(
|
94
|
-
`Cannot concat with ${module.readableIdentifier(
|
95
|
-
requestShortener
|
96
|
-
)} because of ${problem.readableIdentifier(
|
97
|
-
requestShortener
|
98
|
-
)}${reasonWithPrefix}`
|
99
|
-
);
|
100
|
-
}
|
101
|
-
};
|
78
|
+
const getInnerBailoutReason = (module, requestShortener) => {
|
79
|
+
const reason = bailoutReasonMap.get(module);
|
80
|
+
if (typeof reason === "function") return reason(requestShortener);
|
81
|
+
return reason;
|
82
|
+
};
|
102
83
|
|
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
|
-
|
84
|
+
const formatBailoutWarning = (module, problem) => requestShortener => {
|
85
|
+
if (typeof problem === "function") {
|
86
|
+
return formatBailoutReason(
|
87
|
+
`Cannot concat with ${module.readableIdentifier(
|
88
|
+
requestShortener
|
89
|
+
)}: ${problem(requestShortener)}`
|
90
|
+
);
|
91
|
+
}
|
92
|
+
const reason = getInnerBailoutReason(module, requestShortener);
|
93
|
+
const reasonWithPrefix = reason ? `: ${reason}` : "";
|
94
|
+
if (module === problem) {
|
95
|
+
return formatBailoutReason(
|
96
|
+
`Cannot concat with ${module.readableIdentifier(
|
97
|
+
requestShortener
|
98
|
+
)}${reasonWithPrefix}`
|
99
|
+
);
|
100
|
+
} else {
|
101
|
+
return formatBailoutReason(
|
102
|
+
`Cannot concat with ${module.readableIdentifier(
|
103
|
+
requestShortener
|
104
|
+
)} because of ${problem.readableIdentifier(
|
105
|
+
requestShortener
|
106
|
+
)}${reasonWithPrefix}`
|
107
|
+
);
|
108
|
+
}
|
109
|
+
};
|
129
110
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
111
|
+
compilation.hooks.optimizeChunkModules.tapAsync(
|
112
|
+
{
|
113
|
+
name: "ModuleConcatenationPlugin",
|
114
|
+
stage: STAGE_DEFAULT
|
115
|
+
},
|
116
|
+
(allChunks, modules, callback) => {
|
117
|
+
const logger = compilation.getLogger(
|
118
|
+
"webpack.ModuleConcatenationPlugin"
|
119
|
+
);
|
120
|
+
const { chunkGraph, moduleGraph } = compilation;
|
121
|
+
const relevantModules = [];
|
122
|
+
const possibleInners = new Set();
|
123
|
+
const context = {
|
124
|
+
chunkGraph,
|
125
|
+
moduleGraph
|
126
|
+
};
|
127
|
+
logger.time("select relevant modules");
|
128
|
+
for (const module of modules) {
|
129
|
+
let canBeRoot = true;
|
130
|
+
let canBeInner = true;
|
131
|
+
|
132
|
+
const bailoutReason = module.getConcatenationBailoutReason(context);
|
133
|
+
if (bailoutReason) {
|
134
|
+
setBailoutReason(module, bailoutReason);
|
135
|
+
continue;
|
136
|
+
}
|
135
137
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
138
|
+
// Must not be an async module
|
139
|
+
if (moduleGraph.isAsync(module)) {
|
140
|
+
setBailoutReason(module, `Module is async`);
|
141
|
+
continue;
|
142
|
+
}
|
141
143
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
144
|
+
// Must be in strict mode
|
145
|
+
if (!module.buildInfo.strict) {
|
146
|
+
setBailoutReason(module, `Module is not in strict mode`);
|
147
|
+
continue;
|
148
|
+
}
|
147
149
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
exportInfo.isReexport() && !exportInfo.getTarget(moduleGraph)
|
154
|
-
);
|
155
|
-
});
|
156
|
-
if (unknownReexports.length > 0) {
|
157
|
-
setBailoutReason(
|
158
|
-
module,
|
159
|
-
`Reexports in this module do not have a static target (${Array.from(
|
160
|
-
unknownReexports,
|
161
|
-
exportInfo =>
|
162
|
-
`${
|
163
|
-
exportInfo.name || "other exports"
|
164
|
-
}: ${exportInfo.getUsedInfo()}`
|
165
|
-
).join(", ")})`
|
166
|
-
);
|
167
|
-
continue;
|
168
|
-
}
|
150
|
+
// Module must be in any chunk (we don't want to do useless work)
|
151
|
+
if (chunkGraph.getNumberOfModuleChunks(module) === 0) {
|
152
|
+
setBailoutReason(module, "Module is not in any chunk");
|
153
|
+
continue;
|
154
|
+
}
|
169
155
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
156
|
+
// Exports must be known (and not dynamic)
|
157
|
+
const exportsInfo = moduleGraph.getExportsInfo(module);
|
158
|
+
const relevantExports = exportsInfo.getRelevantExports(undefined);
|
159
|
+
const unknownReexports = relevantExports.filter(exportInfo => {
|
160
|
+
return (
|
161
|
+
exportInfo.isReexport() && !exportInfo.getTarget(moduleGraph)
|
175
162
|
);
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
)
|
187
|
-
|
188
|
-
|
163
|
+
});
|
164
|
+
if (unknownReexports.length > 0) {
|
165
|
+
setBailoutReason(
|
166
|
+
module,
|
167
|
+
`Reexports in this module do not have a static target (${Array.from(
|
168
|
+
unknownReexports,
|
169
|
+
exportInfo =>
|
170
|
+
`${
|
171
|
+
exportInfo.name || "other exports"
|
172
|
+
}: ${exportInfo.getUsedInfo()}`
|
173
|
+
).join(", ")})`
|
174
|
+
);
|
175
|
+
continue;
|
176
|
+
}
|
189
177
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
178
|
+
// Root modules must have a static list of exports
|
179
|
+
const unknownProvidedExports = relevantExports.filter(
|
180
|
+
exportInfo => {
|
181
|
+
return exportInfo.provided !== true;
|
194
182
|
}
|
183
|
+
);
|
184
|
+
if (unknownProvidedExports.length > 0) {
|
185
|
+
setBailoutReason(
|
186
|
+
module,
|
187
|
+
`List of module exports is dynamic (${Array.from(
|
188
|
+
unknownProvidedExports,
|
189
|
+
exportInfo =>
|
190
|
+
`${
|
191
|
+
exportInfo.name || "other exports"
|
192
|
+
}: ${exportInfo.getProvidedInfo()} and ${exportInfo.getUsedInfo()}`
|
193
|
+
).join(", ")})`
|
194
|
+
);
|
195
|
+
canBeRoot = false;
|
196
|
+
}
|
195
197
|
|
196
|
-
|
197
|
-
|
198
|
+
// Module must not be an entry point
|
199
|
+
if (chunkGraph.isEntryModule(module)) {
|
200
|
+
setInnerBailoutReason(module, "Module is an entry point");
|
201
|
+
canBeInner = false;
|
202
|
+
}
|
203
|
+
|
204
|
+
if (canBeRoot) relevantModules.push(module);
|
205
|
+
if (canBeInner) possibleInners.add(module);
|
206
|
+
}
|
207
|
+
logger.timeEnd("select relevant modules");
|
208
|
+
logger.debug(
|
209
|
+
`${relevantModules.length} potential root modules, ${possibleInners.size} potential inner modules`
|
210
|
+
);
|
211
|
+
// sort by depth
|
212
|
+
// modules with lower depth are more likely suited as roots
|
213
|
+
// this improves performance, because modules already selected as inner are skipped
|
214
|
+
logger.time("sort relevant modules");
|
215
|
+
relevantModules.sort((a, b) => {
|
216
|
+
return moduleGraph.getDepth(a) - moduleGraph.getDepth(b);
|
217
|
+
});
|
218
|
+
logger.timeEnd("sort relevant modules");
|
219
|
+
|
220
|
+
/** @type {Statistics} */
|
221
|
+
const stats = {
|
222
|
+
cached: 0,
|
223
|
+
alreadyInConfig: 0,
|
224
|
+
invalidModule: 0,
|
225
|
+
incorrectChunks: 0,
|
226
|
+
incorrectDependency: 0,
|
227
|
+
incorrectModuleDependency: 0,
|
228
|
+
incorrectChunksOfImporter: 0,
|
229
|
+
incorrectRuntimeCondition: 0,
|
230
|
+
importerFailed: 0,
|
231
|
+
added: 0
|
232
|
+
};
|
233
|
+
let statsCandidates = 0;
|
234
|
+
let statsSizeSum = 0;
|
235
|
+
let statsEmptyConfigurations = 0;
|
236
|
+
|
237
|
+
logger.time("find modules to concatenate");
|
238
|
+
const concatConfigurations = [];
|
239
|
+
const usedAsInner = new Set();
|
240
|
+
for (const currentRoot of relevantModules) {
|
241
|
+
// when used by another configuration as inner:
|
242
|
+
// the other configuration is better and we can skip this one
|
243
|
+
// TODO reconsider that when it's only used in a different runtime
|
244
|
+
if (usedAsInner.has(currentRoot)) continue;
|
245
|
+
|
246
|
+
let chunkRuntime = undefined;
|
247
|
+
for (const r of chunkGraph.getModuleRuntimes(currentRoot)) {
|
248
|
+
chunkRuntime = mergeRuntimeOwned(chunkRuntime, r);
|
198
249
|
}
|
199
|
-
|
200
|
-
|
201
|
-
|
250
|
+
const exportsInfo = moduleGraph.getExportsInfo(currentRoot);
|
251
|
+
const filteredRuntime = filterRuntime(chunkRuntime, r =>
|
252
|
+
exportsInfo.isModuleUsed(r)
|
253
|
+
);
|
254
|
+
const activeRuntime =
|
255
|
+
filteredRuntime === true
|
256
|
+
? chunkRuntime
|
257
|
+
: filteredRuntime === false
|
258
|
+
? undefined
|
259
|
+
: filteredRuntime;
|
260
|
+
|
261
|
+
// create a configuration with the root
|
262
|
+
const currentConfiguration = new ConcatConfiguration(
|
263
|
+
currentRoot,
|
264
|
+
activeRuntime
|
202
265
|
);
|
203
|
-
// sort by depth
|
204
|
-
// modules with lower depth are more likely suited as roots
|
205
|
-
// this improves performance, because modules already selected as inner are skipped
|
206
|
-
logger.time("sort relevant modules");
|
207
|
-
relevantModules.sort((a, b) => {
|
208
|
-
return moduleGraph.getDepth(a) - moduleGraph.getDepth(b);
|
209
|
-
});
|
210
|
-
logger.timeEnd("sort relevant modules");
|
211
|
-
|
212
|
-
logger.time("find modules to concatenate");
|
213
|
-
const concatConfigurations = [];
|
214
|
-
const usedAsInner = new Set();
|
215
|
-
for (const currentRoot of relevantModules) {
|
216
|
-
// when used by another configuration as inner:
|
217
|
-
// the other configuration is better and we can skip this one
|
218
|
-
if (usedAsInner.has(currentRoot)) continue;
|
219
|
-
|
220
|
-
let chunkRuntime = undefined;
|
221
|
-
for (const r of chunkGraph.getModuleRuntimes(currentRoot)) {
|
222
|
-
chunkRuntime = mergeRuntimeOwned(chunkRuntime, r);
|
223
|
-
}
|
224
|
-
const exportsInfo = moduleGraph.getExportsInfo(currentRoot);
|
225
|
-
const filteredRuntime = filterRuntime(chunkRuntime, r =>
|
226
|
-
exportsInfo.isModuleUsed(r)
|
227
|
-
);
|
228
|
-
const activeRuntime =
|
229
|
-
filteredRuntime === true
|
230
|
-
? chunkRuntime
|
231
|
-
: filteredRuntime === false
|
232
|
-
? undefined
|
233
|
-
: filteredRuntime;
|
234
|
-
|
235
|
-
// create a configuration with the root
|
236
|
-
const currentConfiguration = new ConcatConfiguration(
|
237
|
-
currentRoot,
|
238
|
-
activeRuntime
|
239
|
-
);
|
240
266
|
|
241
|
-
|
242
|
-
|
267
|
+
// cache failures to add modules
|
268
|
+
const failureCache = new Map();
|
243
269
|
|
244
|
-
|
245
|
-
|
246
|
-
|
270
|
+
// potential optional import candidates
|
271
|
+
/** @type {Set<Module>} */
|
272
|
+
const candidates = new Set();
|
247
273
|
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
274
|
+
// try to add all imports
|
275
|
+
for (const imp of this._getImports(
|
276
|
+
compilation,
|
277
|
+
currentRoot,
|
278
|
+
activeRuntime
|
279
|
+
)) {
|
280
|
+
candidates.add(imp);
|
281
|
+
}
|
256
282
|
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
currentConfiguration.addWarning(imp, problem);
|
276
|
-
|
277
|
-
// roll back
|
278
|
-
currentConfiguration.rollback(backup);
|
279
|
-
} else {
|
280
|
-
for (const c of impCandidates) {
|
281
|
-
candidates.add(c);
|
282
|
-
}
|
283
|
-
}
|
284
|
-
}
|
285
|
-
if (!currentConfiguration.isEmpty()) {
|
286
|
-
concatConfigurations.push(currentConfiguration);
|
287
|
-
for (const module of currentConfiguration.getModules()) {
|
288
|
-
if (module !== currentConfiguration.rootModule) {
|
289
|
-
usedAsInner.add(module);
|
290
|
-
}
|
291
|
-
}
|
283
|
+
for (const imp of candidates) {
|
284
|
+
const impCandidates = new Set();
|
285
|
+
const problem = this._tryToAdd(
|
286
|
+
compilation,
|
287
|
+
currentConfiguration,
|
288
|
+
imp,
|
289
|
+
chunkRuntime,
|
290
|
+
activeRuntime,
|
291
|
+
possibleInners,
|
292
|
+
impCandidates,
|
293
|
+
failureCache,
|
294
|
+
chunkGraph,
|
295
|
+
true,
|
296
|
+
stats
|
297
|
+
);
|
298
|
+
if (problem) {
|
299
|
+
failureCache.set(imp, problem);
|
300
|
+
currentConfiguration.addWarning(imp, problem);
|
292
301
|
} else {
|
293
|
-
const
|
294
|
-
|
295
|
-
);
|
296
|
-
for (const warning of currentConfiguration.getWarningsSorted()) {
|
297
|
-
optimizationBailouts.push(
|
298
|
-
formatBailoutWarning(warning[0], warning[1])
|
299
|
-
);
|
302
|
+
for (const c of impCandidates) {
|
303
|
+
candidates.add(c);
|
300
304
|
}
|
301
305
|
}
|
302
306
|
}
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
logger.time(`sort concat configurations`);
|
312
|
-
concatConfigurations.sort((a, b) => {
|
313
|
-
return b.modules.size - a.modules.size;
|
314
|
-
});
|
315
|
-
logger.timeEnd(`sort concat configurations`);
|
316
|
-
const usedModules = new Set();
|
317
|
-
|
318
|
-
logger.time("create concatenated modules");
|
319
|
-
asyncLib.each(
|
320
|
-
concatConfigurations,
|
321
|
-
(concatConfiguration, callback) => {
|
322
|
-
const rootModule = concatConfiguration.rootModule;
|
323
|
-
|
324
|
-
// Avoid overlapping configurations
|
325
|
-
// TODO: remove this when todo above is fixed
|
326
|
-
if (usedModules.has(rootModule)) return callback();
|
327
|
-
const modules = concatConfiguration.getModules();
|
328
|
-
for (const m of modules) {
|
329
|
-
usedModules.add(m);
|
307
|
+
statsCandidates += candidates.size;
|
308
|
+
if (!currentConfiguration.isEmpty()) {
|
309
|
+
const modules = currentConfiguration.getModules();
|
310
|
+
statsSizeSum += modules.size;
|
311
|
+
concatConfigurations.push(currentConfiguration);
|
312
|
+
for (const module of modules) {
|
313
|
+
if (module !== currentConfiguration.rootModule) {
|
314
|
+
usedAsInner.add(module);
|
330
315
|
}
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
316
|
+
}
|
317
|
+
} else {
|
318
|
+
statsEmptyConfigurations++;
|
319
|
+
const optimizationBailouts = moduleGraph.getOptimizationBailout(
|
320
|
+
currentRoot
|
321
|
+
);
|
322
|
+
for (const warning of currentConfiguration.getWarningsSorted()) {
|
323
|
+
optimizationBailouts.push(
|
324
|
+
formatBailoutWarning(warning[0], warning[1])
|
338
325
|
);
|
326
|
+
}
|
327
|
+
}
|
328
|
+
}
|
329
|
+
logger.timeEnd("find modules to concatenate");
|
330
|
+
logger.debug(
|
331
|
+
`${
|
332
|
+
concatConfigurations.length
|
333
|
+
} successful concat configurations (avg size: ${
|
334
|
+
statsSizeSum / concatConfigurations.length
|
335
|
+
}), ${statsEmptyConfigurations} bailed out completely`
|
336
|
+
);
|
337
|
+
logger.debug(
|
338
|
+
`${statsCandidates} candidates were considered for adding (${stats.cached} cached failure, ${stats.alreadyInConfig} already in config, ${stats.invalidModule} invalid module, ${stats.incorrectChunks} incorrect chunks, ${stats.incorrectDependency} incorrect dependency, ${stats.incorrectChunksOfImporter} incorrect chunks of importer, ${stats.incorrectModuleDependency} incorrect module dependency, ${stats.incorrectRuntimeCondition} incorrect runtime condition, ${stats.importerFailed} importer failed, ${stats.added} added)`
|
339
|
+
);
|
340
|
+
// HACK: Sort configurations by length and start with the longest one
|
341
|
+
// to get the biggest groups possible. Used modules are marked with usedModules
|
342
|
+
// TODO: Allow to reuse existing configuration while trying to add dependencies.
|
343
|
+
// This would improve performance. O(n^2) -> O(n)
|
344
|
+
logger.time(`sort concat configurations`);
|
345
|
+
concatConfigurations.sort((a, b) => {
|
346
|
+
return b.modules.size - a.modules.size;
|
347
|
+
});
|
348
|
+
logger.timeEnd(`sort concat configurations`);
|
349
|
+
const usedModules = new Set();
|
350
|
+
|
351
|
+
logger.time("create concatenated modules");
|
352
|
+
asyncLib.each(
|
353
|
+
concatConfigurations,
|
354
|
+
(concatConfiguration, callback) => {
|
355
|
+
const rootModule = concatConfiguration.rootModule;
|
356
|
+
|
357
|
+
// Avoid overlapping configurations
|
358
|
+
// TODO: remove this when todo above is fixed
|
359
|
+
if (usedModules.has(rootModule)) return callback();
|
360
|
+
const modules = concatConfiguration.getModules();
|
361
|
+
for (const m of modules) {
|
362
|
+
usedModules.add(m);
|
363
|
+
}
|
339
364
|
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
365
|
+
// Create a new ConcatenatedModule
|
366
|
+
let newModule = ConcatenatedModule.create(
|
367
|
+
rootModule,
|
368
|
+
modules,
|
369
|
+
concatConfiguration.runtime,
|
370
|
+
compiler.root
|
371
|
+
);
|
344
372
|
|
345
|
-
|
346
|
-
|
373
|
+
const build = () => {
|
374
|
+
newModule.build(
|
375
|
+
compiler.options,
|
376
|
+
compilation,
|
377
|
+
null,
|
378
|
+
null,
|
379
|
+
err => {
|
347
380
|
if (err) {
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
if (cacheModule) {
|
352
|
-
cacheModule.updateCacheModule(newModule);
|
353
|
-
newModule = cacheModule;
|
354
|
-
}
|
355
|
-
|
356
|
-
build();
|
357
|
-
});
|
358
|
-
};
|
359
|
-
|
360
|
-
const build = () => {
|
361
|
-
newModule.build(
|
362
|
-
compiler.options,
|
363
|
-
compilation,
|
364
|
-
null,
|
365
|
-
null,
|
366
|
-
err => {
|
367
|
-
if (err) {
|
368
|
-
if (!err.module) {
|
369
|
-
err.module = newModule;
|
370
|
-
}
|
371
|
-
return callback(err);
|
381
|
+
if (!err.module) {
|
382
|
+
err.module = newModule;
|
372
383
|
}
|
373
|
-
|
384
|
+
return callback(err);
|
374
385
|
}
|
375
|
-
|
376
|
-
|
386
|
+
integrate();
|
387
|
+
}
|
388
|
+
);
|
389
|
+
};
|
377
390
|
|
378
|
-
|
379
|
-
|
380
|
-
|
391
|
+
const integrate = () => {
|
392
|
+
ChunkGraph.setChunkGraphForModule(newModule, chunkGraph);
|
393
|
+
ModuleGraph.setModuleGraphForModule(newModule, moduleGraph);
|
381
394
|
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
395
|
+
for (const warning of concatConfiguration.getWarningsSorted()) {
|
396
|
+
moduleGraph
|
397
|
+
.getOptimizationBailout(newModule)
|
398
|
+
.push(formatBailoutWarning(warning[0], warning[1]));
|
399
|
+
}
|
400
|
+
moduleGraph.cloneModuleAttributes(rootModule, newModule);
|
401
|
+
for (const m of modules) {
|
402
|
+
// add to builtModules when one of the included modules was built
|
403
|
+
if (compilation.builtModules.has(m)) {
|
404
|
+
compilation.builtModules.add(newModule);
|
386
405
|
}
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
c.originModule === m &&
|
401
|
-
!(
|
402
|
-
c.dependency instanceof HarmonyImportDependency &&
|
403
|
-
modules.has(c.module)
|
404
|
-
)
|
405
|
-
);
|
406
|
-
}
|
407
|
-
);
|
408
|
-
// remove module from chunk
|
409
|
-
for (const chunk of chunkGraph.getModuleChunksIterable(
|
410
|
-
rootModule
|
411
|
-
)) {
|
412
|
-
chunkGraph.disconnectChunkAndModule(chunk, m);
|
406
|
+
if (m !== rootModule) {
|
407
|
+
// attach external references to the concatenated module too
|
408
|
+
moduleGraph.copyOutgoingModuleConnections(
|
409
|
+
m,
|
410
|
+
newModule,
|
411
|
+
c => {
|
412
|
+
return (
|
413
|
+
c.originModule === m &&
|
414
|
+
!(
|
415
|
+
c.dependency instanceof HarmonyImportDependency &&
|
416
|
+
modules.has(c.module)
|
417
|
+
)
|
418
|
+
);
|
413
419
|
}
|
420
|
+
);
|
421
|
+
// remove module from chunk
|
422
|
+
for (const chunk of chunkGraph.getModuleChunksIterable(
|
423
|
+
rootModule
|
424
|
+
)) {
|
425
|
+
chunkGraph.disconnectChunkAndModule(chunk, m);
|
414
426
|
}
|
415
427
|
}
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
c
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
restore();
|
446
|
-
},
|
447
|
-
err => {
|
448
|
-
logger.timeEnd("create concatenated modules");
|
449
|
-
process.nextTick(() => callback(err));
|
450
|
-
}
|
451
|
-
);
|
452
|
-
}
|
453
|
-
);
|
454
|
-
}
|
455
|
-
);
|
428
|
+
}
|
429
|
+
compilation.modules.delete(rootModule);
|
430
|
+
// remove module from chunk
|
431
|
+
chunkGraph.replaceModule(rootModule, newModule);
|
432
|
+
// replace module references with the concatenated module
|
433
|
+
moduleGraph.moveModuleConnections(rootModule, newModule, c => {
|
434
|
+
const otherModule =
|
435
|
+
c.module === rootModule ? c.originModule : c.module;
|
436
|
+
const innerConnection =
|
437
|
+
c.dependency instanceof HarmonyImportDependency &&
|
438
|
+
modules.has(otherModule);
|
439
|
+
return !innerConnection;
|
440
|
+
});
|
441
|
+
// add concatenated module to the compilation
|
442
|
+
compilation.modules.add(newModule);
|
443
|
+
|
444
|
+
callback();
|
445
|
+
};
|
446
|
+
|
447
|
+
build();
|
448
|
+
},
|
449
|
+
err => {
|
450
|
+
logger.timeEnd("create concatenated modules");
|
451
|
+
process.nextTick(() => callback(err));
|
452
|
+
}
|
453
|
+
);
|
454
|
+
}
|
455
|
+
);
|
456
|
+
});
|
456
457
|
}
|
457
458
|
|
458
459
|
/**
|
@@ -505,6 +506,8 @@ class ModuleConcatenationPlugin {
|
|
505
506
|
* @param {Set<Module>} candidates list of potential candidates (will be added to)
|
506
507
|
* @param {Map<Module, Module | function(RequestShortener): string>} failureCache cache for problematic modules to be more performant
|
507
508
|
* @param {ChunkGraph} chunkGraph the chunk graph
|
509
|
+
* @param {boolean} avoidMutateOnFailure avoid mutating the config when adding fails
|
510
|
+
* @param {Statistics} statistics gathering metrics
|
508
511
|
* @returns {Module | function(RequestShortener): string} the problematic module
|
509
512
|
*/
|
510
513
|
_tryToAdd(
|
@@ -516,20 +519,25 @@ class ModuleConcatenationPlugin {
|
|
516
519
|
possibleModules,
|
517
520
|
candidates,
|
518
521
|
failureCache,
|
519
|
-
chunkGraph
|
522
|
+
chunkGraph,
|
523
|
+
avoidMutateOnFailure,
|
524
|
+
statistics
|
520
525
|
) {
|
521
526
|
const cacheEntry = failureCache.get(module);
|
522
527
|
if (cacheEntry) {
|
528
|
+
statistics.cached++;
|
523
529
|
return cacheEntry;
|
524
530
|
}
|
525
531
|
|
526
532
|
// Already added?
|
527
533
|
if (config.has(module)) {
|
534
|
+
statistics.alreadyInConfig++;
|
528
535
|
return null;
|
529
536
|
}
|
530
537
|
|
531
538
|
// Not possible to add?
|
532
539
|
if (!possibleModules.has(module)) {
|
540
|
+
statistics.invalidModule++;
|
533
541
|
failureCache.set(module, module); // cache failures for performance
|
534
542
|
return module;
|
535
543
|
}
|
@@ -537,137 +545,106 @@ class ModuleConcatenationPlugin {
|
|
537
545
|
// Module must be in the correct chunks
|
538
546
|
const missingChunks = Array.from(
|
539
547
|
chunkGraph.getModuleChunksIterable(config.rootModule)
|
540
|
-
)
|
541
|
-
.filter(chunk => !chunkGraph.isModuleInChunk(module, chunk))
|
542
|
-
.map(chunk => chunk.name || "unnamed chunk(s)");
|
548
|
+
).filter(chunk => !chunkGraph.isModuleInChunk(module, chunk));
|
543
549
|
if (missingChunks.length > 0) {
|
544
|
-
const
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
550
|
+
const problem = requestShortener => {
|
551
|
+
const missingChunksList = Array.from(
|
552
|
+
new Set(missingChunks.map(chunk => chunk.name || "unnamed chunk(s)"))
|
553
|
+
).sort();
|
554
|
+
const chunks = Array.from(
|
555
|
+
new Set(
|
556
|
+
Array.from(chunkGraph.getModuleChunksIterable(module)).map(
|
557
|
+
chunk => chunk.name || "unnamed chunk(s)"
|
558
|
+
)
|
549
559
|
)
|
550
|
-
)
|
551
|
-
|
552
|
-
const problem = requestShortener =>
|
553
|
-
`Module ${module.readableIdentifier(
|
560
|
+
).sort();
|
561
|
+
return `Module ${module.readableIdentifier(
|
554
562
|
requestShortener
|
555
563
|
)} is not in the same chunk(s) (expected in chunk(s) ${missingChunksList.join(
|
556
564
|
", "
|
557
565
|
)}, module is in chunk(s) ${chunks.join(", ")})`;
|
566
|
+
};
|
567
|
+
statistics.incorrectChunks++;
|
558
568
|
failureCache.set(module, problem); // cache failures for performance
|
559
569
|
return problem;
|
560
570
|
}
|
561
571
|
|
562
|
-
// Add the module
|
563
|
-
config.add(module);
|
564
|
-
|
565
572
|
const moduleGraph = compilation.moduleGraph;
|
566
573
|
|
567
|
-
const incomingConnections =
|
568
|
-
|
569
|
-
)
|
570
|
-
// We are not interested in inactive connections
|
571
|
-
if (!connection.isActive(runtime)) return false;
|
572
|
-
|
573
|
-
// Include, but do not analyse further, connections from non-modules
|
574
|
-
if (!connection.originModule) return true;
|
575
|
-
|
576
|
-
// Ignore connection from orphan modules
|
577
|
-
if (chunkGraph.getNumberOfModuleChunks(connection.originModule) === 0)
|
578
|
-
return false;
|
574
|
+
const incomingConnections = moduleGraph.getIncomingConnectionsByOriginModule(
|
575
|
+
module
|
576
|
+
);
|
579
577
|
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
578
|
+
const incomingConnectionsFromNonModules =
|
579
|
+
incomingConnections.get(null) || incomingConnections.get(undefined);
|
580
|
+
if (incomingConnectionsFromNonModules) {
|
581
|
+
const activeNonModulesConnections = incomingConnectionsFromNonModules.filter(
|
582
|
+
connection => {
|
583
|
+
// We are not interested in inactive connections
|
584
|
+
// or connections without dependency
|
585
|
+
return connection.isActive(runtime) || connection.dependency;
|
586
|
+
}
|
587
|
+
);
|
588
|
+
if (activeNonModulesConnections.length > 0) {
|
589
|
+
const problem = requestShortener => {
|
590
|
+
const importingExplanations = new Set(
|
591
|
+
activeNonModulesConnections.map(c => c.explanation).filter(Boolean)
|
592
|
+
);
|
593
|
+
const explanations = Array.from(importingExplanations).sort();
|
594
|
+
return `Module ${module.readableIdentifier(
|
595
|
+
requestShortener
|
596
|
+
)} is referenced ${
|
597
|
+
explanations.length > 0
|
598
|
+
? `by: ${explanations.join(", ")}`
|
599
|
+
: "in an unsupported way"
|
600
|
+
}`;
|
601
|
+
};
|
602
|
+
statistics.incorrectDependency++;
|
603
|
+
failureCache.set(module, problem); // cache failures for performance
|
604
|
+
return problem;
|
584
605
|
}
|
606
|
+
}
|
585
607
|
|
586
|
-
|
587
|
-
|
608
|
+
/** @type {Map<Module, readonly ModuleGraph.ModuleGraphConnection[]>} */
|
609
|
+
const incomingConnectionsFromModules = new Map();
|
610
|
+
for (const [originModule, connections] of incomingConnections) {
|
611
|
+
if (originModule) {
|
612
|
+
// Ignore connection from orphan modules
|
613
|
+
if (chunkGraph.getNumberOfModuleChunks(originModule) === 0) continue;
|
614
|
+
|
615
|
+
// We don't care for connections from other runtimes
|
616
|
+
let originRuntime = undefined;
|
617
|
+
for (const r of chunkGraph.getModuleRuntimes(originModule)) {
|
618
|
+
originRuntime = mergeRuntimeOwned(originRuntime, r);
|
619
|
+
}
|
588
620
|
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
);
|
595
|
-
if (nonHarmonyConnections.length > 0) {
|
596
|
-
const problem = requestShortener => {
|
597
|
-
const importingModules = new Set(
|
598
|
-
nonHarmonyConnections.map(c => c.originModule).filter(Boolean)
|
599
|
-
);
|
600
|
-
const importingExplanations = new Set(
|
601
|
-
nonHarmonyConnections.map(c => c.explanation).filter(Boolean)
|
602
|
-
);
|
603
|
-
const importingModuleTypes = new Map(
|
604
|
-
Array.from(importingModules).map(
|
605
|
-
m =>
|
606
|
-
/** @type {[Module, Set<string>]} */ ([
|
607
|
-
m,
|
608
|
-
new Set(
|
609
|
-
nonHarmonyConnections
|
610
|
-
.filter(c => c.originModule === m)
|
611
|
-
.map(c => c.dependency.type)
|
612
|
-
.sort()
|
613
|
-
)
|
614
|
-
])
|
615
|
-
)
|
621
|
+
if (!intersectRuntime(runtime, originRuntime)) continue;
|
622
|
+
|
623
|
+
// We are not interested in inactive connections
|
624
|
+
const activeConnections = connections.filter(connection =>
|
625
|
+
connection.isActive(runtime)
|
616
626
|
);
|
617
|
-
|
618
|
-
.
|
619
|
-
|
620
|
-
`${m.readableIdentifier(
|
621
|
-
requestShortener
|
622
|
-
)} (referenced with ${Array.from(
|
623
|
-
importingModuleTypes.get(m)
|
624
|
-
).join(", ")})`
|
625
|
-
)
|
626
|
-
.sort();
|
627
|
-
const explanations = Array.from(importingExplanations).sort();
|
628
|
-
if (names.length > 0 && explanations.length === 0) {
|
629
|
-
return `Module ${module.readableIdentifier(
|
630
|
-
requestShortener
|
631
|
-
)} is referenced from these modules with unsupported syntax: ${names.join(
|
632
|
-
", "
|
633
|
-
)}`;
|
634
|
-
} else if (names.length === 0 && explanations.length > 0) {
|
635
|
-
return `Module ${module.readableIdentifier(
|
636
|
-
requestShortener
|
637
|
-
)} is referenced by: ${explanations.join(", ")}`;
|
638
|
-
} else if (names.length > 0 && explanations.length > 0) {
|
639
|
-
return `Module ${module.readableIdentifier(
|
640
|
-
requestShortener
|
641
|
-
)} is referenced from these modules with unsupported syntax: ${names.join(
|
642
|
-
", "
|
643
|
-
)} and by: ${explanations.join(", ")}`;
|
644
|
-
} else {
|
645
|
-
return `Module ${module.readableIdentifier(
|
646
|
-
requestShortener
|
647
|
-
)} is referenced in a unsupported way`;
|
648
|
-
}
|
649
|
-
};
|
650
|
-
failureCache.set(module, problem); // cache failures for performance
|
651
|
-
return problem;
|
627
|
+
if (activeConnections.length > 0)
|
628
|
+
incomingConnectionsFromModules.set(originModule, activeConnections);
|
629
|
+
}
|
652
630
|
}
|
653
631
|
|
632
|
+
const incomingModules = Array.from(incomingConnectionsFromModules.keys());
|
633
|
+
|
654
634
|
// Module must be in the same chunks like the referencing module
|
655
|
-
const
|
635
|
+
const otherChunkModules = incomingModules.filter(originModule => {
|
656
636
|
for (const chunk of chunkGraph.getModuleChunksIterable(
|
657
637
|
config.rootModule
|
658
638
|
)) {
|
659
|
-
if (!chunkGraph.isModuleInChunk(
|
639
|
+
if (!chunkGraph.isModuleInChunk(originModule, chunk)) {
|
660
640
|
return true;
|
661
641
|
}
|
662
642
|
}
|
663
643
|
return false;
|
664
644
|
});
|
665
|
-
if (
|
645
|
+
if (otherChunkModules.length > 0) {
|
666
646
|
const problem = requestShortener => {
|
667
|
-
const
|
668
|
-
otherChunkConnections.map(c => c.originModule)
|
669
|
-
);
|
670
|
-
const names = Array.from(importingModules)
|
647
|
+
const names = otherChunkModules
|
671
648
|
.map(m => m.readableIdentifier(requestShortener))
|
672
649
|
.sort();
|
673
650
|
return `Module ${module.readableIdentifier(
|
@@ -676,41 +653,90 @@ class ModuleConcatenationPlugin {
|
|
676
653
|
", "
|
677
654
|
)}`;
|
678
655
|
};
|
656
|
+
statistics.incorrectChunksOfImporter++;
|
657
|
+
failureCache.set(module, problem); // cache failures for performance
|
658
|
+
return problem;
|
659
|
+
}
|
660
|
+
|
661
|
+
/** @type {Map<Module, readonly ModuleGraph.ModuleGraphConnection[]>} */
|
662
|
+
const nonHarmonyConnections = new Map();
|
663
|
+
for (const [originModule, connections] of incomingConnectionsFromModules) {
|
664
|
+
const selected = connections.filter(
|
665
|
+
connection =>
|
666
|
+
!connection.dependency ||
|
667
|
+
!(connection.dependency instanceof HarmonyImportDependency)
|
668
|
+
);
|
669
|
+
if (selected.length > 0)
|
670
|
+
nonHarmonyConnections.set(originModule, connections);
|
671
|
+
}
|
672
|
+
if (nonHarmonyConnections.size > 0) {
|
673
|
+
const problem = requestShortener => {
|
674
|
+
const names = Array.from(nonHarmonyConnections)
|
675
|
+
.map(([originModule, connections]) => {
|
676
|
+
return `${originModule.readableIdentifier(
|
677
|
+
requestShortener
|
678
|
+
)} (referenced with ${Array.from(
|
679
|
+
new Set(
|
680
|
+
connections
|
681
|
+
.map(c => c.dependency && c.dependency.type)
|
682
|
+
.filter(Boolean)
|
683
|
+
)
|
684
|
+
)
|
685
|
+
.sort()
|
686
|
+
.join(", ")})`;
|
687
|
+
})
|
688
|
+
.sort();
|
689
|
+
return `Module ${module.readableIdentifier(
|
690
|
+
requestShortener
|
691
|
+
)} is referenced from these modules with unsupported syntax: ${names.join(
|
692
|
+
", "
|
693
|
+
)}`;
|
694
|
+
};
|
695
|
+
statistics.incorrectModuleDependency++;
|
679
696
|
failureCache.set(module, problem); // cache failures for performance
|
680
697
|
return problem;
|
681
698
|
}
|
682
699
|
|
683
700
|
if (runtime !== undefined && typeof runtime !== "string") {
|
684
701
|
// Module must be consistently referenced in the same runtimes
|
685
|
-
/** @type {
|
686
|
-
const
|
687
|
-
for (const
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
);
|
699
|
-
|
700
|
-
|
702
|
+
/** @type {{ originModule: Module, runtimeCondition: RuntimeSpec }[]} */
|
703
|
+
const otherRuntimeConnections = [];
|
704
|
+
outer: for (const [
|
705
|
+
originModule,
|
706
|
+
connections
|
707
|
+
] of incomingConnectionsFromModules) {
|
708
|
+
/** @type {false | RuntimeSpec} */
|
709
|
+
let currentRuntimeCondition = false;
|
710
|
+
for (const connection of connections) {
|
711
|
+
const runtimeCondition = filterRuntime(runtime, runtime => {
|
712
|
+
return connection.isTargetActive(runtime);
|
713
|
+
});
|
714
|
+
if (runtimeCondition === false) continue;
|
715
|
+
if (runtimeCondition === true) continue outer;
|
716
|
+
if (currentRuntimeCondition !== false) {
|
717
|
+
currentRuntimeCondition = mergeRuntime(
|
718
|
+
currentRuntimeCondition,
|
719
|
+
runtimeCondition
|
720
|
+
);
|
721
|
+
} else {
|
722
|
+
currentRuntimeCondition = runtimeCondition;
|
723
|
+
}
|
724
|
+
}
|
725
|
+
if (currentRuntimeCondition !== false) {
|
726
|
+
otherRuntimeConnections.push({
|
727
|
+
originModule,
|
728
|
+
runtimeCondition: currentRuntimeCondition
|
729
|
+
});
|
701
730
|
}
|
702
731
|
}
|
703
|
-
const otherRuntimeConnections = Array.from(runtimeConditionMap).filter(
|
704
|
-
([, runtimeCondition]) => typeof runtimeCondition !== "boolean"
|
705
|
-
);
|
706
732
|
if (otherRuntimeConnections.length > 0) {
|
707
733
|
const problem = requestShortener => {
|
708
734
|
return `Module ${module.readableIdentifier(
|
709
735
|
requestShortener
|
710
736
|
)} is runtime-dependent referenced by these modules: ${Array.from(
|
711
737
|
otherRuntimeConnections,
|
712
|
-
(
|
713
|
-
`${
|
738
|
+
({ originModule, runtimeCondition }) =>
|
739
|
+
`${originModule.readableIdentifier(
|
714
740
|
requestShortener
|
715
741
|
)} (expected runtime ${runtimeToString(
|
716
742
|
runtime
|
@@ -719,14 +745,21 @@ class ModuleConcatenationPlugin {
|
|
719
745
|
)})`
|
720
746
|
).join(", ")}`;
|
721
747
|
};
|
748
|
+
statistics.incorrectRuntimeCondition++;
|
722
749
|
failureCache.set(module, problem); // cache failures for performance
|
723
750
|
return problem;
|
724
751
|
}
|
725
752
|
}
|
726
753
|
|
727
|
-
|
728
|
-
|
729
|
-
|
754
|
+
let backup;
|
755
|
+
if (avoidMutateOnFailure) {
|
756
|
+
backup = config.snapshot();
|
757
|
+
}
|
758
|
+
|
759
|
+
// Add the module
|
760
|
+
config.add(module);
|
761
|
+
|
762
|
+
incomingModules.sort(compareModulesByIdentifier);
|
730
763
|
|
731
764
|
// Every module which depends on the added module must be in the configuration too.
|
732
765
|
for (const originModule of incomingModules) {
|
@@ -739,9 +772,13 @@ class ModuleConcatenationPlugin {
|
|
739
772
|
possibleModules,
|
740
773
|
candidates,
|
741
774
|
failureCache,
|
742
|
-
chunkGraph
|
775
|
+
chunkGraph,
|
776
|
+
false,
|
777
|
+
statistics
|
743
778
|
);
|
744
779
|
if (problem) {
|
780
|
+
if (backup !== undefined) config.rollback(backup);
|
781
|
+
statistics.importerFailed++;
|
745
782
|
failureCache.set(module, problem); // cache failures for performance
|
746
783
|
return problem;
|
747
784
|
}
|
@@ -751,6 +788,7 @@ class ModuleConcatenationPlugin {
|
|
751
788
|
for (const imp of this._getImports(compilation, module, runtime)) {
|
752
789
|
candidates.add(imp);
|
753
790
|
}
|
791
|
+
statistics.added++;
|
754
792
|
return null;
|
755
793
|
}
|
756
794
|
}
|
@@ -763,15 +801,15 @@ class ConcatConfiguration {
|
|
763
801
|
constructor(rootModule, runtime) {
|
764
802
|
this.rootModule = rootModule;
|
765
803
|
this.runtime = runtime;
|
766
|
-
/** @type {
|
767
|
-
this.modules = new
|
768
|
-
this.modules.
|
769
|
-
/** @type {
|
770
|
-
this.warnings = new
|
804
|
+
/** @type {Set<Module>} */
|
805
|
+
this.modules = new Set();
|
806
|
+
this.modules.add(rootModule);
|
807
|
+
/** @type {Map<Module, Module | function(RequestShortener): string>} */
|
808
|
+
this.warnings = new Map();
|
771
809
|
}
|
772
810
|
|
773
811
|
add(module) {
|
774
|
-
this.modules.
|
812
|
+
this.modules.add(module);
|
775
813
|
}
|
776
814
|
|
777
815
|
has(module) {
|
@@ -788,7 +826,7 @@ class ConcatConfiguration {
|
|
788
826
|
|
789
827
|
getWarningsSorted() {
|
790
828
|
return new Map(
|
791
|
-
this.warnings
|
829
|
+
Array.from(this.warnings).sort((a, b) => {
|
792
830
|
const ai = a[0].identifier();
|
793
831
|
const bi = b[0].identifier();
|
794
832
|
if (ai < bi) return -1;
|
@@ -802,17 +840,22 @@ class ConcatConfiguration {
|
|
802
840
|
* @returns {Set<Module>} modules as set
|
803
841
|
*/
|
804
842
|
getModules() {
|
805
|
-
return this.modules
|
843
|
+
return this.modules;
|
806
844
|
}
|
807
845
|
|
808
846
|
snapshot() {
|
809
|
-
|
810
|
-
this.modules = this.modules.createChild();
|
811
|
-
return base;
|
847
|
+
return this.modules.size;
|
812
848
|
}
|
813
849
|
|
814
850
|
rollback(snapshot) {
|
815
|
-
|
851
|
+
const modules = this.modules;
|
852
|
+
for (const m of modules) {
|
853
|
+
if (snapshot === 0) {
|
854
|
+
modules.delete(m);
|
855
|
+
} else {
|
856
|
+
snapshot--;
|
857
|
+
}
|
858
|
+
}
|
816
859
|
}
|
817
860
|
}
|
818
861
|
|