webpack 5.107.0 → 5.107.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.
- package/lib/BannerPlugin.js +3 -4
- package/lib/Chunk.js +21 -25
- package/lib/ChunkGroup.js +57 -15
- package/lib/Compilation.js +33 -11
- package/lib/Compiler.js +27 -3
- package/lib/ContextModuleFactory.js +45 -38
- package/lib/EvalSourceMapDevToolPlugin.js +0 -1
- package/lib/ExportsInfo.js +30 -34
- package/lib/ExternalModule.js +15 -11
- package/lib/ExternalModuleFactoryPlugin.js +2 -1
- package/lib/Module.js +1 -1
- package/lib/ModuleNotFoundError.js +10 -0
- package/lib/ModuleSourceTypeConstants.js +24 -22
- package/lib/MultiCompiler.js +14 -0
- package/lib/NormalModule.js +531 -53
- package/lib/NormalModuleFactory.js +38 -26
- package/lib/ProgressPlugin.js +1 -1
- package/lib/RuntimePlugin.js +1 -1
- package/lib/SourceMapDevToolPlugin.js +335 -57
- package/lib/Template.js +1 -1
- package/lib/TemplatedPathPlugin.js +22 -4
- package/lib/asset/AssetBytesGenerator.js +6 -6
- package/lib/asset/AssetGenerator.js +14 -14
- package/lib/asset/AssetModulesPlugin.js +3 -7
- package/lib/asset/AssetSourceGenerator.js +6 -6
- package/lib/buildChunkGraph.js +24 -2
- package/lib/cache/getLazyHashedEtag.js +9 -2
- package/lib/css/CssModulesPlugin.js +2 -2
- package/lib/dependencies/CommonJsImportsParserPlugin.js +108 -1
- package/lib/dependencies/CssUrlDependency.js +3 -2
- package/lib/dependencies/HarmonyDetectionParserPlugin.js +21 -1
- package/lib/dependencies/HarmonyExportInitFragment.js +8 -9
- package/lib/dependencies/HtmlInlineScriptDependency.js +3 -14
- package/lib/dependencies/HtmlInlineStyleDependency.js +17 -0
- package/lib/dependencies/HtmlScriptSrcDependency.js +265 -65
- package/lib/dependencies/HtmlSourceDependency.js +21 -2
- package/lib/dependencies/WorkerPlugin.js +18 -4
- package/lib/hmr/LazyCompilationPlugin.js +104 -0
- package/lib/html/HtmlGenerator.js +81 -33
- package/lib/html/HtmlModulesPlugin.js +87 -28
- package/lib/html/walkHtmlTokens.js +641 -125
- package/lib/index.js +2 -0
- package/lib/javascript/JavascriptModulesPlugin.js +2 -2
- package/lib/javascript/JavascriptParser.js +1 -1
- package/lib/library/ModuleLibraryPlugin.js +30 -24
- package/lib/node/NodeWatchFileSystem.js +37 -22
- package/lib/optimize/ConcatenatedModule.js +3 -2
- package/lib/optimize/SideEffectsFlagPlugin.js +1 -2
- package/lib/optimize/SplitChunksPlugin.js +4 -4
- package/lib/runtime/AutoPublicPathRuntimeModule.js +3 -3
- package/lib/runtime/GetChunkFilenameRuntimeModule.js +5 -5
- package/lib/sharing/ConsumeSharedPlugin.js +2 -8
- package/lib/sharing/ProvideSharedPlugin.js +4 -4
- package/lib/util/fs.js +6 -1
- package/lib/wasm-async/AsyncWebAssemblyModulesPlugin.js +1 -2
- package/package.json +5 -5
- package/schemas/WebpackOptions.check.js +1 -1
- package/schemas/WebpackOptions.json +11 -9
- package/schemas/plugins/container/ContainerReferencePlugin.check.js +1 -1
- package/schemas/plugins/container/ContainerReferencePlugin.json +1 -0
- package/schemas/plugins/container/ExternalsType.check.js +1 -1
- package/schemas/plugins/container/ModuleFederationPlugin.check.js +1 -1
- package/schemas/plugins/container/ModuleFederationPlugin.json +1 -0
- package/types.d.ts +472 -149
package/lib/NormalModule.js
CHANGED
|
@@ -61,6 +61,7 @@ const parseJson = require("./util/parseJson");
|
|
|
61
61
|
/** @typedef {import("../declarations/WebpackOptions").ResolveOptions} ResolveOptions */
|
|
62
62
|
/** @typedef {import("../declarations/WebpackOptions").NoParse} NoParse */
|
|
63
63
|
/** @typedef {import("./config/defaults").WebpackOptionsNormalizedWithDefaults} WebpackOptions */
|
|
64
|
+
/** @typedef {import("./Dependency")} Dependency */
|
|
64
65
|
/** @typedef {import("./Dependency").UpdateHashContext} UpdateHashContext */
|
|
65
66
|
/** @typedef {import("./Generator")} Generator */
|
|
66
67
|
/** @typedef {import("./Generator").GenerateErrorFn} GenerateErrorFn */
|
|
@@ -87,6 +88,10 @@ const parseJson = require("./util/parseJson");
|
|
|
87
88
|
/** @typedef {import("./ModuleGraphConnection").ConnectionState} ConnectionState */
|
|
88
89
|
/** @typedef {import("./NormalModuleFactory")} NormalModuleFactory */
|
|
89
90
|
/** @typedef {import("./NormalModuleFactory").NormalModuleTypes} NormalModuleTypes */
|
|
91
|
+
/** @typedef {import("./NormalModuleFactory").ParserByType} ParserByType */
|
|
92
|
+
/** @typedef {import("./NormalModuleFactory").ParserOptionsByType} ParserOptionsByType */
|
|
93
|
+
/** @typedef {import("./NormalModuleFactory").GeneratorByType} GeneratorByType */
|
|
94
|
+
/** @typedef {import("./NormalModuleFactory").GeneratorOptionsByType} GeneratorOptionsByType */
|
|
90
95
|
/** @typedef {import("./NormalModuleFactory").ResourceSchemeData} ResourceSchemeData */
|
|
91
96
|
/** @typedef {import("./Parser")} Parser */
|
|
92
97
|
/** @typedef {import("./Parser").PreparsedAst} PreparsedAst */
|
|
@@ -126,6 +131,488 @@ const getExtractSourceMap = memoize(() => require("./util/extractSourceMap"));
|
|
|
126
131
|
|
|
127
132
|
const getValidate = memoize(() => require("schema-utils").validate);
|
|
128
133
|
|
|
134
|
+
const getHarmonyImportSideEffectDependency = memoize(() =>
|
|
135
|
+
require("./dependencies/HarmonyImportSideEffectDependency")
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* @param {NormalModule} mod the module
|
|
140
|
+
* @param {ModuleGraph} moduleGraph the module graph
|
|
141
|
+
* @param {Dependency} dep the dep that triggered the bailout
|
|
142
|
+
*/
|
|
143
|
+
const recordSideEffectsBailout = (mod, moduleGraph, dep) => {
|
|
144
|
+
if (mod._addedSideEffectsBailout === undefined) {
|
|
145
|
+
mod._addedSideEffectsBailout = new WeakSet();
|
|
146
|
+
} else if (mod._addedSideEffectsBailout.has(moduleGraph)) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
mod._addedSideEffectsBailout.add(moduleGraph);
|
|
150
|
+
moduleGraph
|
|
151
|
+
.getOptimizationBailout(mod)
|
|
152
|
+
.push(
|
|
153
|
+
() =>
|
|
154
|
+
`Dependency (${dep.type}) with side effects at ${formatLocation(dep.loc)}`
|
|
155
|
+
);
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
// Maximum recursive descent depth before switching to the iterative walker.
|
|
159
|
+
// #20986 reported overflow around 1300 modules in webpack 5.107.0 where each
|
|
160
|
+
// step consumed two stack frames (`NormalModule.getSideEffectsConnectionState`
|
|
161
|
+
// plus `HarmonyImportSideEffectDependency.getModuleEvaluationSideEffectsState`).
|
|
162
|
+
// `walkSideEffectsRecursive` folds the second call into the first and uses
|
|
163
|
+
// one frame per module, so this limit caps the native stack at half the depth
|
|
164
|
+
// where the original code overflowed — well within the safe range across
|
|
165
|
+
// platforms while keeping the common (shallow) case purely recursive.
|
|
166
|
+
const SIDE_EFFECTS_RECURSION_LIMIT = 2000;
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Iterative form of the side-effects walker. Used as a fallback once the
|
|
170
|
+
* recursive form reaches `SIDE_EFFECTS_RECURSION_LIMIT` so deep chains
|
|
171
|
+
* (#20986) don't overflow V8's stack. Safe to enter while ancestors set
|
|
172
|
+
* `_isEvaluatingSideEffects` on their own modules — those are treated as
|
|
173
|
+
* `CIRCULAR_CONNECTION` if revisited, matching the original recursive
|
|
174
|
+
* behavior.
|
|
175
|
+
* @param {NormalModule} rootMod the module to walk
|
|
176
|
+
* @param {ModuleGraph} moduleGraph the module graph
|
|
177
|
+
* @returns {ConnectionState} the side-effects connection state
|
|
178
|
+
*/
|
|
179
|
+
const walkSideEffectsIterative = (rootMod, moduleGraph) => {
|
|
180
|
+
const SideEffectDep = getHarmonyImportSideEffectDependency();
|
|
181
|
+
|
|
182
|
+
/** @type {NormalModule[]} */
|
|
183
|
+
const modStack = [rootMod];
|
|
184
|
+
/** @type {Dependency[][]} */
|
|
185
|
+
const depsStack = [rootMod.dependencies];
|
|
186
|
+
const indexStack = [0];
|
|
187
|
+
/** @type {ConnectionState[]} */
|
|
188
|
+
const currentStack = [false];
|
|
189
|
+
rootMod._isEvaluatingSideEffects = true;
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Result from a just-popped child frame, to be applied to the new
|
|
193
|
+
* top's current dep. `undefined` means "no pending; advance".
|
|
194
|
+
* @type {ConnectionState | undefined}
|
|
195
|
+
*/
|
|
196
|
+
let pending;
|
|
197
|
+
|
|
198
|
+
while (modStack.length > 0) {
|
|
199
|
+
const top = modStack.length - 1;
|
|
200
|
+
const topMod = modStack[top];
|
|
201
|
+
const deps = depsStack[top];
|
|
202
|
+
let index = indexStack[top];
|
|
203
|
+
let current = currentStack[top];
|
|
204
|
+
|
|
205
|
+
if (pending !== undefined) {
|
|
206
|
+
const state = pending;
|
|
207
|
+
pending = undefined;
|
|
208
|
+
const dep = deps[index];
|
|
209
|
+
|
|
210
|
+
if (state === true) {
|
|
211
|
+
recordSideEffectsBailout(topMod, moduleGraph, dep);
|
|
212
|
+
topMod._isEvaluatingSideEffects = false;
|
|
213
|
+
// `true` is monotonic — safe to memoize regardless of cycle
|
|
214
|
+
// status, matching the direct-bailout branch below.
|
|
215
|
+
topMod._sideEffectsStateGraph = moduleGraph;
|
|
216
|
+
topMod._sideEffectsStateValue = true;
|
|
217
|
+
modStack.pop();
|
|
218
|
+
depsStack.pop();
|
|
219
|
+
indexStack.pop();
|
|
220
|
+
currentStack.pop();
|
|
221
|
+
pending = true;
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
if (state !== ModuleGraphConnection.CIRCULAR_CONNECTION) {
|
|
225
|
+
current = ModuleGraphConnection.addConnectionStates(current, state);
|
|
226
|
+
}
|
|
227
|
+
index++;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
let descended = false;
|
|
231
|
+
const depCount = deps.length;
|
|
232
|
+
while (index < depCount) {
|
|
233
|
+
const dep = deps[index];
|
|
234
|
+
/** @type {ConnectionState} */
|
|
235
|
+
let state;
|
|
236
|
+
|
|
237
|
+
if (dep instanceof SideEffectDep) {
|
|
238
|
+
const refModule = moduleGraph.getModule(dep);
|
|
239
|
+
if (!refModule) {
|
|
240
|
+
state = true;
|
|
241
|
+
} else if (refModule instanceof NormalModule) {
|
|
242
|
+
// Cache hit
|
|
243
|
+
if (refModule._sideEffectsStateGraph === moduleGraph) {
|
|
244
|
+
state = /** @type {ConnectionState} */ (
|
|
245
|
+
refModule._sideEffectsStateValue
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
// Fast-path checks inlined to avoid the helper call.
|
|
249
|
+
else if (refModule.factoryMeta !== undefined) {
|
|
250
|
+
if (refModule.factoryMeta.sideEffectFree) {
|
|
251
|
+
state = false;
|
|
252
|
+
} else if (refModule.factoryMeta.sideEffectFree === false) {
|
|
253
|
+
state = true;
|
|
254
|
+
} else if (
|
|
255
|
+
!(
|
|
256
|
+
refModule.buildMeta !== undefined &&
|
|
257
|
+
refModule.buildMeta.sideEffectFree
|
|
258
|
+
)
|
|
259
|
+
) {
|
|
260
|
+
state = true;
|
|
261
|
+
} else if (refModule._isEvaluatingSideEffects) {
|
|
262
|
+
_sideEffectsCircularSeen = true;
|
|
263
|
+
state = ModuleGraphConnection.CIRCULAR_CONNECTION;
|
|
264
|
+
} else {
|
|
265
|
+
// Descend
|
|
266
|
+
indexStack[top] = index;
|
|
267
|
+
currentStack[top] = current;
|
|
268
|
+
refModule._isEvaluatingSideEffects = true;
|
|
269
|
+
modStack.push(refModule);
|
|
270
|
+
depsStack.push(refModule.dependencies);
|
|
271
|
+
indexStack.push(0);
|
|
272
|
+
currentStack.push(false);
|
|
273
|
+
descended = true;
|
|
274
|
+
break;
|
|
275
|
+
}
|
|
276
|
+
} else if (
|
|
277
|
+
!(
|
|
278
|
+
refModule.buildMeta !== undefined &&
|
|
279
|
+
refModule.buildMeta.sideEffectFree
|
|
280
|
+
)
|
|
281
|
+
) {
|
|
282
|
+
state = true;
|
|
283
|
+
} else if (refModule._isEvaluatingSideEffects) {
|
|
284
|
+
_sideEffectsCircularSeen = true;
|
|
285
|
+
state = ModuleGraphConnection.CIRCULAR_CONNECTION;
|
|
286
|
+
} else {
|
|
287
|
+
// Descend
|
|
288
|
+
indexStack[top] = index;
|
|
289
|
+
currentStack[top] = current;
|
|
290
|
+
refModule._isEvaluatingSideEffects = true;
|
|
291
|
+
modStack.push(refModule);
|
|
292
|
+
depsStack.push(refModule.dependencies);
|
|
293
|
+
indexStack.push(0);
|
|
294
|
+
currentStack.push(false);
|
|
295
|
+
descended = true;
|
|
296
|
+
break;
|
|
297
|
+
}
|
|
298
|
+
} else {
|
|
299
|
+
_sideEffectsCircularSeen = true;
|
|
300
|
+
state = refModule.getSideEffectsConnectionState(moduleGraph);
|
|
301
|
+
}
|
|
302
|
+
} else {
|
|
303
|
+
state = dep.getModuleEvaluationSideEffectsState(moduleGraph);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (state === true) {
|
|
307
|
+
recordSideEffectsBailout(topMod, moduleGraph, dep);
|
|
308
|
+
topMod._isEvaluatingSideEffects = false;
|
|
309
|
+
topMod._sideEffectsStateGraph = moduleGraph;
|
|
310
|
+
topMod._sideEffectsStateValue = true;
|
|
311
|
+
modStack.pop();
|
|
312
|
+
depsStack.pop();
|
|
313
|
+
indexStack.pop();
|
|
314
|
+
currentStack.pop();
|
|
315
|
+
pending = true;
|
|
316
|
+
descended = true;
|
|
317
|
+
break;
|
|
318
|
+
}
|
|
319
|
+
if (state !== ModuleGraphConnection.CIRCULAR_CONNECTION) {
|
|
320
|
+
current = ModuleGraphConnection.addConnectionStates(current, state);
|
|
321
|
+
}
|
|
322
|
+
index++;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (descended) continue;
|
|
326
|
+
|
|
327
|
+
topMod._isEvaluatingSideEffects = false;
|
|
328
|
+
if (!_sideEffectsCircularSeen) {
|
|
329
|
+
topMod._sideEffectsStateGraph = moduleGraph;
|
|
330
|
+
topMod._sideEffectsStateValue = current;
|
|
331
|
+
}
|
|
332
|
+
pending = current;
|
|
333
|
+
modStack.pop();
|
|
334
|
+
depsStack.pop();
|
|
335
|
+
indexStack.pop();
|
|
336
|
+
currentStack.pop();
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
return /** @type {ConnectionState} */ (pending);
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Tracks whether a cycle (CIRCULAR_CONNECTION) was encountered anywhere
|
|
344
|
+
* in the currently-executing walk. The walker uses this to decide whether
|
|
345
|
+
* an intermediate result is safe to memoize on the module: a result
|
|
346
|
+
* computed in the presence of a cycle can differ from the result computed
|
|
347
|
+
* fresh, because cycle short-circuiting hides the contribution of the
|
|
348
|
+
* back-edge target. Reset to `false` at the top-level entry; read and
|
|
349
|
+
* propagated by each recursive frame.
|
|
350
|
+
*/
|
|
351
|
+
let _sideEffectsCircularSeen = false;
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Walks back up a stack of linear-chain ancestors, applying the result
|
|
355
|
+
* `state` of the chain's tail to each ancestor. Each ancestor in the
|
|
356
|
+
* stack had exactly one `HarmonyImportSideEffectDependency` returning
|
|
357
|
+
* `state`, so its result is just `state` (with the usual aggregation
|
|
358
|
+
* rules) and we can avoid building per-frame `current` accumulators.
|
|
359
|
+
* @param {(NormalModule | Dependency)[] | null} ancestors interleaved stack of `[mod, sideEffectDep, mod, sideEffectDep, …]` in descent order; `null` if there were none
|
|
360
|
+
* @param {ConnectionState} state result from the chain's tail
|
|
361
|
+
* @param {ModuleGraph} moduleGraph the module graph
|
|
362
|
+
* @returns {ConnectionState} the root ancestor's result
|
|
363
|
+
*/
|
|
364
|
+
const propagateLinearResult = (ancestors, state, moduleGraph) => {
|
|
365
|
+
if (ancestors === null) return state;
|
|
366
|
+
while (ancestors.length > 0) {
|
|
367
|
+
const dep = /** @type {Dependency} */ (ancestors.pop());
|
|
368
|
+
const ancestor = /** @type {NormalModule} */ (ancestors.pop());
|
|
369
|
+
ancestor._isEvaluatingSideEffects = false;
|
|
370
|
+
|
|
371
|
+
if (state === true) {
|
|
372
|
+
recordSideEffectsBailout(ancestor, moduleGraph, dep);
|
|
373
|
+
// `true` is monotonic — safe to cache regardless of cycle status.
|
|
374
|
+
ancestor._sideEffectsStateGraph = moduleGraph;
|
|
375
|
+
ancestor._sideEffectsStateValue = true;
|
|
376
|
+
} else if (state === ModuleGraphConnection.CIRCULAR_CONNECTION) {
|
|
377
|
+
// CIRCULAR_CONNECTION is filtered before folding into `current`,
|
|
378
|
+
// so the ancestor's `current` stays at its initial `false`. From
|
|
379
|
+
// this point upward the propagated state is `false`, and the
|
|
380
|
+
// cycle taint prevents memoization further up (handled by
|
|
381
|
+
// `_sideEffectsCircularSeen`).
|
|
382
|
+
state = false;
|
|
383
|
+
} else if (!_sideEffectsCircularSeen) {
|
|
384
|
+
ancestor._sideEffectsStateGraph = moduleGraph;
|
|
385
|
+
ancestor._sideEffectsStateValue = state;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
return state;
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Recursive form of the side-effects walker. Folds the descent through
|
|
393
|
+
* `HarmonyImportSideEffectDependency.getModuleEvaluationSideEffectsState`
|
|
394
|
+
* directly into the loop so each module costs only one V8 stack frame
|
|
395
|
+
* (vs. two in the original recursive code).
|
|
396
|
+
*
|
|
397
|
+
* Linear-chain heads (modules with exactly one
|
|
398
|
+
* `HarmonyImportSideEffectDependency` to another `NormalModule`) are
|
|
399
|
+
* walked iteratively inside the function via an explicit
|
|
400
|
+
* `linearAncestors` stack — no additional V8 frame per descent — and
|
|
401
|
+
* their results are propagated back up by `propagateLinearResult`. This
|
|
402
|
+
* keeps stack consumption at O(1) for the common deep-import-chain
|
|
403
|
+
* pattern that motivated #20986 and also avoids the heavier iterative
|
|
404
|
+
* fallback.
|
|
405
|
+
*
|
|
406
|
+
* Falls back to `walkSideEffectsIterative` only when a *non-linear*
|
|
407
|
+
* walk reaches `SIDE_EFFECTS_RECURSION_LIMIT` — i.e. a deep tree, where
|
|
408
|
+
* each level genuinely needs its own recursion frame.
|
|
409
|
+
*
|
|
410
|
+
* Caches the result on the module when the walk did not encounter a
|
|
411
|
+
* cycle, so subsequent queries (e.g. repeated lookups during
|
|
412
|
+
* `SideEffectsFlagPlugin`'s incoming-connection optimization and its
|
|
413
|
+
* `exportInfo.getTarget` callbacks) return in O(1).
|
|
414
|
+
* @param {NormalModule} mod the module being walked
|
|
415
|
+
* @param {ModuleGraph} moduleGraph the module graph
|
|
416
|
+
* @param {number} depth current recursion depth (only counts true V8 frames)
|
|
417
|
+
* @param {EXPECTED_ANY} SideEffectDep `HarmonyImportSideEffectDependency` constructor, resolved once at the public entry to avoid repeated `require` lookups in the recursive call
|
|
418
|
+
* @returns {ConnectionState} the side-effects connection state
|
|
419
|
+
*/
|
|
420
|
+
const walkSideEffectsRecursive = (mod, moduleGraph, depth, SideEffectDep) => {
|
|
421
|
+
// Interleaved `[mod, linearDep, mod, linearDep, …]` for the linear
|
|
422
|
+
// chain head; `null` until the first descent.
|
|
423
|
+
/** @type {(NormalModule | Dependency)[] | null} */
|
|
424
|
+
let linearAncestors = null;
|
|
425
|
+
|
|
426
|
+
// Walk the linear-chain head iteratively. Every loop iteration peels
|
|
427
|
+
// off one module without consuming a V8 stack frame.
|
|
428
|
+
while (true) {
|
|
429
|
+
if (mod._sideEffectsStateGraph === moduleGraph) {
|
|
430
|
+
return propagateLinearResult(
|
|
431
|
+
linearAncestors,
|
|
432
|
+
/** @type {ConnectionState} */ (mod._sideEffectsStateValue),
|
|
433
|
+
moduleGraph
|
|
434
|
+
);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
if (mod.factoryMeta !== undefined) {
|
|
438
|
+
if (mod.factoryMeta.sideEffectFree) {
|
|
439
|
+
return propagateLinearResult(linearAncestors, false, moduleGraph);
|
|
440
|
+
}
|
|
441
|
+
if (mod.factoryMeta.sideEffectFree === false) {
|
|
442
|
+
return propagateLinearResult(linearAncestors, true, moduleGraph);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
if (!(mod.buildMeta !== undefined && mod.buildMeta.sideEffectFree)) {
|
|
446
|
+
return propagateLinearResult(linearAncestors, true, moduleGraph);
|
|
447
|
+
}
|
|
448
|
+
if (mod._isEvaluatingSideEffects) {
|
|
449
|
+
_sideEffectsCircularSeen = true;
|
|
450
|
+
return propagateLinearResult(
|
|
451
|
+
linearAncestors,
|
|
452
|
+
ModuleGraphConnection.CIRCULAR_CONNECTION,
|
|
453
|
+
moduleGraph
|
|
454
|
+
);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// A real ESM module's `dependencies` typically include one
|
|
458
|
+
// `HarmonyImportSideEffectDependency` plus several non-recursive deps
|
|
459
|
+
// (export specifiers, const dependencies, …) that report
|
|
460
|
+
// `false`/`CIRCULAR_CONNECTION` from
|
|
461
|
+
// `getModuleEvaluationSideEffectsState`. Walk the deps in order
|
|
462
|
+
// here: as long as at most one is a `SideEffectDep` and no
|
|
463
|
+
// non-recursive dep triggers a bailout or contributes a non-`false`
|
|
464
|
+
// state, we can still tail-call iteratively through that one
|
|
465
|
+
// `SideEffectDep` — no V8 frame needed. This is what keeps the
|
|
466
|
+
// 1300-module cyclic chain from #20986 from overflowing V8's stack
|
|
467
|
+
// even though each generated module has multiple `dependencies`.
|
|
468
|
+
const deps = mod.dependencies;
|
|
469
|
+
/** @type {Dependency | null} */
|
|
470
|
+
let linearDep = null;
|
|
471
|
+
/** @type {ConnectionState} */
|
|
472
|
+
let nonRecursiveCurrent = false;
|
|
473
|
+
let linearOk = true;
|
|
474
|
+
for (let i = 0; i < deps.length; i++) {
|
|
475
|
+
const dep = deps[i];
|
|
476
|
+
if (dep instanceof SideEffectDep) {
|
|
477
|
+
if (linearDep !== null) {
|
|
478
|
+
// Two `SideEffectDep`s in the same module — fall back to
|
|
479
|
+
// the general walk so each can recurse normally.
|
|
480
|
+
linearOk = false;
|
|
481
|
+
break;
|
|
482
|
+
}
|
|
483
|
+
linearDep = dep;
|
|
484
|
+
} else {
|
|
485
|
+
const state = dep.getModuleEvaluationSideEffectsState(moduleGraph);
|
|
486
|
+
if (state === true) {
|
|
487
|
+
recordSideEffectsBailout(mod, moduleGraph, dep);
|
|
488
|
+
mod._sideEffectsStateGraph = moduleGraph;
|
|
489
|
+
mod._sideEffectsStateValue = true;
|
|
490
|
+
return propagateLinearResult(linearAncestors, true, moduleGraph);
|
|
491
|
+
}
|
|
492
|
+
if (state !== ModuleGraphConnection.CIRCULAR_CONNECTION) {
|
|
493
|
+
nonRecursiveCurrent = ModuleGraphConnection.addConnectionStates(
|
|
494
|
+
nonRecursiveCurrent,
|
|
495
|
+
state
|
|
496
|
+
);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
if (!linearOk || nonRecursiveCurrent !== false) {
|
|
502
|
+
// Multiple `SideEffectDep`s, or a non-recursive dep contributed
|
|
503
|
+
// a non-`false` state (e.g. `TRANSITIVE_ONLY`). The linear
|
|
504
|
+
// propagation rule "ancestor's current = chain state" no longer
|
|
505
|
+
// holds, so fall back to the general walk.
|
|
506
|
+
break;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
if (linearDep === null) {
|
|
510
|
+
// No `SideEffectDep` — the module is a leaf as far as the
|
|
511
|
+
// side-effects graph is concerned. Cache and propagate `false`.
|
|
512
|
+
if (!_sideEffectsCircularSeen) {
|
|
513
|
+
mod._sideEffectsStateGraph = moduleGraph;
|
|
514
|
+
mod._sideEffectsStateValue = false;
|
|
515
|
+
}
|
|
516
|
+
return propagateLinearResult(linearAncestors, false, moduleGraph);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
const refModule = moduleGraph.getModule(linearDep);
|
|
520
|
+
if (!refModule) {
|
|
521
|
+
recordSideEffectsBailout(mod, moduleGraph, linearDep);
|
|
522
|
+
mod._sideEffectsStateGraph = moduleGraph;
|
|
523
|
+
mod._sideEffectsStateValue = true;
|
|
524
|
+
return propagateLinearResult(linearAncestors, true, moduleGraph);
|
|
525
|
+
}
|
|
526
|
+
if (!(refModule instanceof NormalModule)) {
|
|
527
|
+
// Non-NormalModule's `getSideEffectsConnectionState` re-enters
|
|
528
|
+
// the public method; defer to the general walk for safety.
|
|
529
|
+
break;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
mod._isEvaluatingSideEffects = true;
|
|
533
|
+
if (linearAncestors === null) linearAncestors = [];
|
|
534
|
+
// Push (mod, linearDep) so `propagateLinearResult` records bailouts
|
|
535
|
+
// against the actual `SideEffectDep` that triggered the descent —
|
|
536
|
+
// which may not be `dependencies[0]` when the module also has
|
|
537
|
+
// export / const dependencies.
|
|
538
|
+
linearAncestors.push(mod, linearDep);
|
|
539
|
+
mod = refModule;
|
|
540
|
+
continue;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// Non-linear walk. Each genuine recursive call costs one V8 frame, so
|
|
544
|
+
// honour the depth limit here.
|
|
545
|
+
if (depth >= SIDE_EFFECTS_RECURSION_LIMIT) {
|
|
546
|
+
return propagateLinearResult(
|
|
547
|
+
linearAncestors,
|
|
548
|
+
walkSideEffectsIterative(mod, moduleGraph),
|
|
549
|
+
moduleGraph
|
|
550
|
+
);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
mod._isEvaluatingSideEffects = true;
|
|
554
|
+
/** @type {ConnectionState} */
|
|
555
|
+
let current = false;
|
|
556
|
+
|
|
557
|
+
for (const dep of mod.dependencies) {
|
|
558
|
+
/** @type {ConnectionState} */
|
|
559
|
+
let state;
|
|
560
|
+
if (dep instanceof SideEffectDep) {
|
|
561
|
+
const refModule = moduleGraph.getModule(dep);
|
|
562
|
+
if (!refModule) {
|
|
563
|
+
state = true;
|
|
564
|
+
} else if (refModule instanceof NormalModule) {
|
|
565
|
+
state = walkSideEffectsRecursive(
|
|
566
|
+
refModule,
|
|
567
|
+
moduleGraph,
|
|
568
|
+
depth + 1,
|
|
569
|
+
SideEffectDep
|
|
570
|
+
);
|
|
571
|
+
} else {
|
|
572
|
+
// Non-NormalModule's `getSideEffectsConnectionState` (notably
|
|
573
|
+
// `ConcatenatedModule` delegating to its root) re-enters the
|
|
574
|
+
// public method and may walk through modules that the outer
|
|
575
|
+
// walk has marked as evaluating. We can't observe whether
|
|
576
|
+
// the inner walk hit a cycle that reflected the outer's
|
|
577
|
+
// state, so treat the walk as cycle-tainted and skip the
|
|
578
|
+
// cache for safety.
|
|
579
|
+
_sideEffectsCircularSeen = true;
|
|
580
|
+
state = refModule.getSideEffectsConnectionState(moduleGraph);
|
|
581
|
+
}
|
|
582
|
+
} else {
|
|
583
|
+
state = dep.getModuleEvaluationSideEffectsState(moduleGraph);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
if (state === true) {
|
|
587
|
+
recordSideEffectsBailout(mod, moduleGraph, dep);
|
|
588
|
+
mod._isEvaluatingSideEffects = false;
|
|
589
|
+
// `true` is monotonic — once any dep declares side effects, the
|
|
590
|
+
// answer is `true` regardless of how cycles resolve, so it's
|
|
591
|
+
// always safe to memoize.
|
|
592
|
+
mod._sideEffectsStateGraph = moduleGraph;
|
|
593
|
+
mod._sideEffectsStateValue = true;
|
|
594
|
+
return propagateLinearResult(linearAncestors, true, moduleGraph);
|
|
595
|
+
}
|
|
596
|
+
if (state !== ModuleGraphConnection.CIRCULAR_CONNECTION) {
|
|
597
|
+
current = ModuleGraphConnection.addConnectionStates(current, state);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
mod._isEvaluatingSideEffects = false;
|
|
602
|
+
|
|
603
|
+
// Only memoize when no cycle has been observed anywhere in the walk
|
|
604
|
+
// since the public entry. A cycle anywhere can affect any ancestor's
|
|
605
|
+
// result (the back-edge target's contribution is hidden by
|
|
606
|
+
// CIRCULAR_CONNECTION short-circuiting), so this single flag is the
|
|
607
|
+
// conservative-but-cheap approximation of "this subtree's result is
|
|
608
|
+
// independent of cycle context". The public entry resets the flag.
|
|
609
|
+
if (!_sideEffectsCircularSeen) {
|
|
610
|
+
mod._sideEffectsStateGraph = moduleGraph;
|
|
611
|
+
mod._sideEffectsStateValue = current;
|
|
612
|
+
}
|
|
613
|
+
return propagateLinearResult(linearAncestors, current, moduleGraph);
|
|
614
|
+
};
|
|
615
|
+
|
|
129
616
|
const ABSOLUTE_PATH_REGEX = /^(?:[a-z]:\\|\\\\|\/)/i;
|
|
130
617
|
|
|
131
618
|
/**
|
|
@@ -229,9 +716,10 @@ const asBuffer = (input) => {
|
|
|
229
716
|
*/
|
|
230
717
|
|
|
231
718
|
/**
|
|
719
|
+
* @template {NormalModuleTypes | ""} [T=NormalModuleTypes | ""]
|
|
232
720
|
* @typedef {object} NormalModuleCreateData
|
|
233
721
|
* @property {string=} layer an optional layer in which the module is
|
|
234
|
-
* @property {
|
|
722
|
+
* @property {T} type module type. When deserializing, this is set to an empty string "".
|
|
235
723
|
* @property {string} request request string
|
|
236
724
|
* @property {string} userRequest request intended by user (without loaders from config)
|
|
237
725
|
* @property {string} rawRequest request without resolving
|
|
@@ -240,10 +728,10 @@ const asBuffer = (input) => {
|
|
|
240
728
|
* @property {(ResourceSchemeData & Partial<ResolveRequest>)=} resourceResolveData resource resolve data
|
|
241
729
|
* @property {string} context context directory for resolving
|
|
242
730
|
* @property {string=} matchResource path + query of the matched resource (virtual)
|
|
243
|
-
* @property {
|
|
244
|
-
* @property {
|
|
245
|
-
* @property {
|
|
246
|
-
* @property {
|
|
731
|
+
* @property {ParserByType[T]} parser the parser used
|
|
732
|
+
* @property {ParserOptionsByType[T]=} parserOptions the options of the parser used
|
|
733
|
+
* @property {GeneratorByType[T]} generator the generator used
|
|
734
|
+
* @property {GeneratorOptionsByType[T]=} generatorOptions the options of the generator used
|
|
247
735
|
* @property {ResolveOptions=} resolveOptions options used for resolving requests from this module
|
|
248
736
|
* @property {boolean} extractSourceMap enable/disable extracting source map
|
|
249
737
|
*/
|
|
@@ -405,15 +893,25 @@ class NormalModule extends Module {
|
|
|
405
893
|
*/
|
|
406
894
|
this._forceBuild = true;
|
|
407
895
|
/**
|
|
408
|
-
* @private
|
|
409
896
|
* @type {boolean}
|
|
410
897
|
*/
|
|
411
898
|
this._isEvaluatingSideEffects = false;
|
|
412
899
|
/**
|
|
413
|
-
* @private
|
|
414
900
|
* @type {WeakSet<ModuleGraph> | undefined}
|
|
415
901
|
*/
|
|
416
902
|
this._addedSideEffectsBailout = undefined;
|
|
903
|
+
/**
|
|
904
|
+
* Memoizes the result of `getSideEffectsConnectionState`. The
|
|
905
|
+
* graph slot keys the cached value to the `ModuleGraph` it was
|
|
906
|
+
* computed against so stale values never leak across compilations
|
|
907
|
+
* — a walk that targets a different graph just overwrites both
|
|
908
|
+
* slots. Populated only for results computed without encountering
|
|
909
|
+
* a circular connection (see `walkSideEffectsRecursive`).
|
|
910
|
+
* @type {ModuleGraph | undefined}
|
|
911
|
+
*/
|
|
912
|
+
this._sideEffectsStateGraph = undefined;
|
|
913
|
+
/** @type {ConnectionState | undefined} */
|
|
914
|
+
this._sideEffectsStateValue = undefined;
|
|
417
915
|
/**
|
|
418
916
|
* @private
|
|
419
917
|
* @type {CodeGenerationResultData}
|
|
@@ -521,6 +1019,11 @@ class NormalModule extends Module {
|
|
|
521
1019
|
this.parserOptions = undefined;
|
|
522
1020
|
this.generator = undefined;
|
|
523
1021
|
this.generatorOptions = undefined;
|
|
1022
|
+
// Drop the side-effects memoization so a long-lived module doesn't
|
|
1023
|
+
// strong-reference a stale `ModuleGraph`/`Compilation` for graphs
|
|
1024
|
+
// that never get re-queried with a fresh one.
|
|
1025
|
+
this._sideEffectsStateGraph = undefined;
|
|
1026
|
+
this._sideEffectsStateValue = undefined;
|
|
524
1027
|
}
|
|
525
1028
|
|
|
526
1029
|
/**
|
|
@@ -693,11 +1196,8 @@ class NormalModule extends Module {
|
|
|
693
1196
|
/** @type {NormalModuleLoaderContext<T>} */
|
|
694
1197
|
const loaderContext = {
|
|
695
1198
|
version: 2,
|
|
696
|
-
/**
|
|
697
|
-
|
|
698
|
-
* @returns {T} options
|
|
699
|
-
*/
|
|
700
|
-
getOptions: (schema) => {
|
|
1199
|
+
/** @type {LoaderContext<EXPECTED_ANY>["getOptions"]} */
|
|
1200
|
+
getOptions: (/** @type {EXPECTED_ANY} */ schema = undefined) => {
|
|
701
1201
|
const loader = this.getCurrentLoader(
|
|
702
1202
|
/** @type {AnyLoaderContext} */
|
|
703
1203
|
(loaderContext)
|
|
@@ -744,6 +1244,7 @@ class NormalModule extends Module {
|
|
|
744
1244
|
|
|
745
1245
|
return /** @type {T} */ (options);
|
|
746
1246
|
},
|
|
1247
|
+
/** @type {LoaderContext<EXPECTED_ANY>["emitWarning"]} */
|
|
747
1248
|
emitWarning: (warning) => {
|
|
748
1249
|
if (!(warning instanceof Error)) {
|
|
749
1250
|
warning = new NonErrorEmittedError(warning);
|
|
@@ -754,6 +1255,7 @@ class NormalModule extends Module {
|
|
|
754
1255
|
})
|
|
755
1256
|
);
|
|
756
1257
|
},
|
|
1258
|
+
/** @type {LoaderContext<EXPECTED_ANY>["emitError"]} */
|
|
757
1259
|
emitError: (error) => {
|
|
758
1260
|
if (!(error instanceof Error)) {
|
|
759
1261
|
error = new NonErrorEmittedError(error);
|
|
@@ -764,6 +1266,7 @@ class NormalModule extends Module {
|
|
|
764
1266
|
})
|
|
765
1267
|
);
|
|
766
1268
|
},
|
|
1269
|
+
/** @type {LoaderContext<EXPECTED_ANY>["getLogger"]} */
|
|
767
1270
|
getLogger: (name) => {
|
|
768
1271
|
const currentLoader = this.getCurrentLoader(
|
|
769
1272
|
/** @type {AnyLoaderContext} */
|
|
@@ -775,9 +1278,11 @@ class NormalModule extends Module {
|
|
|
775
1278
|
.join("|")
|
|
776
1279
|
);
|
|
777
1280
|
},
|
|
1281
|
+
/** @type {LoaderContext<EXPECTED_ANY>["resolve"]} */
|
|
778
1282
|
resolve(context, request, callback) {
|
|
779
1283
|
resolver.resolve({}, context, request, getResolveContext(), callback);
|
|
780
1284
|
},
|
|
1285
|
+
/** @type {LoaderContext<EXPECTED_ANY>["getResolve"]} */
|
|
781
1286
|
getResolve(options) {
|
|
782
1287
|
const child = options ? resolver.withOptions(options) : resolver;
|
|
783
1288
|
return /** @type {ReturnType<import("../declarations/LoaderContext").NormalModuleLoaderContext<T>["getResolve"]>} */ (
|
|
@@ -807,6 +1312,7 @@ class NormalModule extends Module {
|
|
|
807
1312
|
}
|
|
808
1313
|
);
|
|
809
1314
|
},
|
|
1315
|
+
/** @type {LoaderContext<EXPECTED_ANY>["emitFile"]} */
|
|
810
1316
|
emitFile: (name, content, sourceMap, assetInfo) => {
|
|
811
1317
|
const buildInfo = /** @type {BuildInfo} */ (this.buildInfo);
|
|
812
1318
|
|
|
@@ -1453,47 +1959,19 @@ class NormalModule extends Module {
|
|
|
1453
1959
|
* @returns {ConnectionState} how this module should be connected to referencing modules when consumed for side-effects only
|
|
1454
1960
|
*/
|
|
1455
1961
|
getSideEffectsConnectionState(moduleGraph) {
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
if (state === true) {
|
|
1470
|
-
if (
|
|
1471
|
-
this._addedSideEffectsBailout === undefined
|
|
1472
|
-
? ((this._addedSideEffectsBailout = new WeakSet()), true)
|
|
1473
|
-
: !this._addedSideEffectsBailout.has(moduleGraph)
|
|
1474
|
-
) {
|
|
1475
|
-
this._addedSideEffectsBailout.add(moduleGraph);
|
|
1476
|
-
moduleGraph
|
|
1477
|
-
.getOptimizationBailout(this)
|
|
1478
|
-
.push(
|
|
1479
|
-
() =>
|
|
1480
|
-
`Dependency (${
|
|
1481
|
-
dep.type
|
|
1482
|
-
}) with side effects at ${formatLocation(dep.loc)}`
|
|
1483
|
-
);
|
|
1484
|
-
}
|
|
1485
|
-
this._isEvaluatingSideEffects = false;
|
|
1486
|
-
return true;
|
|
1487
|
-
} else if (state !== ModuleGraphConnection.CIRCULAR_CONNECTION) {
|
|
1488
|
-
current = ModuleGraphConnection.addConnectionStates(current, state);
|
|
1489
|
-
}
|
|
1490
|
-
}
|
|
1491
|
-
this._isEvaluatingSideEffects = false;
|
|
1492
|
-
// When caching is implemented here, make sure to not cache when
|
|
1493
|
-
// at least one circular connection was in the loop above
|
|
1494
|
-
return current;
|
|
1495
|
-
}
|
|
1496
|
-
return true;
|
|
1962
|
+
// Save and restore the cycle-tracking flag so that re-entrant calls
|
|
1963
|
+
// (e.g. `ConcatenatedModule.getSideEffectsConnectionState` delegating
|
|
1964
|
+
// back through here) don't clobber the outer walk's state.
|
|
1965
|
+
const savedCircular = _sideEffectsCircularSeen;
|
|
1966
|
+
_sideEffectsCircularSeen = false;
|
|
1967
|
+
const result = walkSideEffectsRecursive(
|
|
1968
|
+
this,
|
|
1969
|
+
moduleGraph,
|
|
1970
|
+
0,
|
|
1971
|
+
getHarmonyImportSideEffectDependency()
|
|
1972
|
+
);
|
|
1973
|
+
_sideEffectsCircularSeen = savedCircular;
|
|
1974
|
+
return result;
|
|
1497
1975
|
}
|
|
1498
1976
|
|
|
1499
1977
|
/**
|