webpack 5.109.0 → 5.109.1
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/bin/webpack.js +12 -0
- package/lib/ChunkGraph.js +17 -15
- package/lib/CompatibilityPlugin.js +31 -0
- package/lib/Compilation.js +9 -2
- package/lib/DefinePlugin.js +37 -11
- package/lib/ExportsInfo.js +22 -5
- package/lib/FileSystemInfo.js +126 -26
- package/lib/FlagDependencyUsagePlugin.js +33 -12
- package/lib/InitFragment.js +20 -32
- package/lib/NormalModule.js +6 -0
- package/lib/RuntimePlugin.js +40 -113
- package/lib/Template.js +23 -3
- package/lib/container/HoistContainerReferencesPlugin.js +47 -55
- package/lib/css/CssParser.js +135 -50
- package/lib/css/syntax.js +862 -765
- package/lib/dependencies/CommonJsExportRequireDependency.js +19 -0
- package/lib/dependencies/HarmonyEvaluatedImportSpecifierDependency.js +2 -1
- package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +17 -9
- package/lib/dependencies/HarmonyImportDependency.js +1 -1
- package/lib/dependencies/HarmonyImportSpecifierDependency.js +10 -7
- package/lib/hmr/lazyCompilationBackend.js +19 -4
- package/lib/html/HtmlGenerator.js +23 -3
- package/lib/html/syntax.js +2485 -2399
- package/lib/ids/IdHelpers.js +24 -10
- package/lib/javascript/JavascriptParser.js +5 -2
- package/lib/javascript/syntax.js +700 -43
- package/lib/node/ReadFileCompileAsyncWasmPlugin.js +10 -2
- package/lib/node/ReadFileCompileWasmPlugin.js +10 -2
- package/lib/optimize/AggressiveMergingPlugin.js +19 -15
- package/lib/optimize/ConcatenatedModule.js +19 -15
- package/lib/optimize/ModuleConcatenationPlugin.js +73 -24
- package/lib/optimize/SplitChunksPlugin.js +146 -44
- package/lib/prefetch/ResourceHintPlugin.js +96 -72
- package/lib/serialization/BinaryMiddleware.js +270 -938
- package/lib/stats/DefaultStatsFactoryPlugin.js +204 -198
- package/lib/stats/DefaultStatsPrinterPlugin.js +24 -166
- package/lib/stats/StatsFactory.js +31 -9
- package/package.json +2 -2
- package/types.d.ts +0 -4
package/bin/webpack.js
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
+
// Cache compiled module bytecode on disk (available since Node.js 22.8)
|
|
6
|
+
// eslint-disable-next-line n/no-unsupported-features/node-builtins
|
|
7
|
+
const { enableCompileCache } = require("module");
|
|
8
|
+
|
|
9
|
+
if (enableCompileCache) {
|
|
10
|
+
try {
|
|
11
|
+
enableCompileCache();
|
|
12
|
+
} catch (_error) {
|
|
13
|
+
// Nothing
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
5
17
|
/**
|
|
6
18
|
* @param {string} command process to run
|
|
7
19
|
* @param {string[]} args command line arguments
|
package/lib/ChunkGraph.js
CHANGED
|
@@ -52,6 +52,19 @@ const EMPTY_SET = new Set();
|
|
|
52
52
|
|
|
53
53
|
const ZERO_BIG_INT = BigInt(0);
|
|
54
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Active state to string. Module-level (depends only on ModuleGraphConnection)
|
|
57
|
+
* so it isn't re-allocated on every getModuleGraphHash call, incl. cache hits.
|
|
58
|
+
* @param {ConnectionState} state state
|
|
59
|
+
* @returns {"F" | "T" | "O"} result
|
|
60
|
+
*/
|
|
61
|
+
const activeStateToString = (state) => {
|
|
62
|
+
if (state === false) return "F";
|
|
63
|
+
if (state === true) return "T";
|
|
64
|
+
if (state === ModuleGraphConnection.TRANSITIVE_ONLY) return "O";
|
|
65
|
+
throw new Error("Not implemented active state");
|
|
66
|
+
};
|
|
67
|
+
|
|
55
68
|
const compareModuleIterables = compareIterables(compareModulesByIdentifier);
|
|
56
69
|
|
|
57
70
|
/** @typedef {(c: Chunk, chunkGraph: ChunkGraph) => boolean} ChunkFilterPredicate */
|
|
@@ -1821,22 +1834,11 @@ Caller might not support runtime-dependent code generation (opt-out via optimiza
|
|
|
1821
1834
|
cgm.graphHashesWithConnections = new RuntimeSpecMap();
|
|
1822
1835
|
}
|
|
1823
1836
|
|
|
1824
|
-
/**
|
|
1825
|
-
* Active state to string.
|
|
1826
|
-
* @param {ConnectionState} state state
|
|
1827
|
-
* @returns {"F" | "T" | "O"} result
|
|
1828
|
-
*/
|
|
1829
|
-
const activeStateToString = (state) => {
|
|
1830
|
-
if (state === false) return "F";
|
|
1831
|
-
if (state === true) return "T";
|
|
1832
|
-
if (state === ModuleGraphConnection.TRANSITIVE_ONLY) return "O";
|
|
1833
|
-
throw new Error("Not implemented active state");
|
|
1834
|
-
};
|
|
1835
|
-
const strict =
|
|
1836
|
-
module.buildMeta &&
|
|
1837
|
-
/** @type {JavascriptModuleBuildMeta} */ (module.buildMeta)
|
|
1838
|
-
.strictHarmonyModule;
|
|
1839
1837
|
return cgm.graphHashesWithConnections.provide(runtime, () => {
|
|
1838
|
+
const strict =
|
|
1839
|
+
module.buildMeta &&
|
|
1840
|
+
/** @type {JavascriptModuleBuildMeta} */ (module.buildMeta)
|
|
1841
|
+
.strictHarmonyModule;
|
|
1840
1842
|
const graphHash = this._getModuleGraphHashBigInt(
|
|
1841
1843
|
cgm,
|
|
1842
1844
|
module,
|
|
@@ -181,6 +181,37 @@ class CompatibilityPlugin {
|
|
|
181
181
|
});
|
|
182
182
|
return true;
|
|
183
183
|
});
|
|
184
|
+
// `const`/`let` are block-pre-walked, by which point the name is no
|
|
185
|
+
// longer free and `hooks.pattern` is not dispatched for it — tag
|
|
186
|
+
// them through the kind-specific declaration hooks instead.
|
|
187
|
+
// Returning nothing lets the variable be defined, keeping the tag.
|
|
188
|
+
for (const hookMap of [
|
|
189
|
+
parser.hooks.varDeclarationConst,
|
|
190
|
+
parser.hooks.varDeclarationLet
|
|
191
|
+
]) {
|
|
192
|
+
hookMap.for(RuntimeGlobals.require).tap(PLUGIN_NAME, (ident) => {
|
|
193
|
+
parser.tagVariable(ident.name, nestedWebpackIdentifierTag, {
|
|
194
|
+
name: `__nested_webpack_require_${
|
|
195
|
+
/** @type {Range} */ (ident.range)[0]
|
|
196
|
+
}__`,
|
|
197
|
+
declaration: {
|
|
198
|
+
updated: false,
|
|
199
|
+
loc: parser.getLocation(ident),
|
|
200
|
+
range: /** @type {Range} */ (ident.range)
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
hookMap.for(RuntimeGlobals.exports).tap(PLUGIN_NAME, (ident) => {
|
|
205
|
+
parser.tagVariable(ident.name, nestedWebpackIdentifierTag, {
|
|
206
|
+
name: "__nested_webpack_exports__",
|
|
207
|
+
declaration: {
|
|
208
|
+
updated: false,
|
|
209
|
+
loc: parser.getLocation(ident),
|
|
210
|
+
range: /** @type {Range} */ (ident.range)
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
}
|
|
184
215
|
// Update single `var __webpack_require__ = {};` and `var __webpack_exports__ = {};` without expression
|
|
185
216
|
parser.hooks.declarator.tap(PLUGIN_NAME, (declarator) => {
|
|
186
217
|
if (
|
package/lib/Compilation.js
CHANGED
|
@@ -3504,6 +3504,10 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
|
|
|
3504
3504
|
this.addModuleQueue.clear();
|
|
3505
3505
|
// lazy barrel only acts during make; release its bookkeeping now
|
|
3506
3506
|
this._lazyBarrelController.clear();
|
|
3507
|
+
// unsafe-cache restore tables are only read during make; release them
|
|
3508
|
+
// so they stop pinning restored modules for the rest of the compilation
|
|
3509
|
+
this._restoredUnsafeCacheModuleEntries.clear();
|
|
3510
|
+
this._restoredUnsafeCacheEntries.clear();
|
|
3507
3511
|
return callback(err);
|
|
3508
3512
|
};
|
|
3509
3513
|
|
|
@@ -4754,10 +4758,13 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
|
|
|
4754
4758
|
for (const module of this.modules) {
|
|
4755
4759
|
const memCache = moduleMemCaches2 && moduleMemCaches2.get(module);
|
|
4756
4760
|
for (const runtime of chunkGraph.getModuleRuntimes(module)) {
|
|
4761
|
+
const cacheKey = memCache
|
|
4762
|
+
? `moduleHash-${getRuntimeKey(runtime)}`
|
|
4763
|
+
: undefined;
|
|
4757
4764
|
if (memCache) {
|
|
4758
4765
|
const digest =
|
|
4759
4766
|
/** @type {string} */
|
|
4760
|
-
(memCache.get(
|
|
4767
|
+
(memCache.get(/** @type {string} */ (cacheKey)));
|
|
4761
4768
|
if (digest !== undefined) {
|
|
4762
4769
|
chunkGraph.setModuleHashes(
|
|
4763
4770
|
module,
|
|
@@ -4781,7 +4788,7 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
|
|
|
4781
4788
|
errors
|
|
4782
4789
|
);
|
|
4783
4790
|
if (memCache) {
|
|
4784
|
-
memCache.set(
|
|
4791
|
+
memCache.set(/** @type {string} */ (cacheKey), digest);
|
|
4785
4792
|
}
|
|
4786
4793
|
}
|
|
4787
4794
|
}
|
package/lib/DefinePlugin.js
CHANGED
|
@@ -628,6 +628,26 @@ const getRuntimeRequirements = (code) => {
|
|
|
628
628
|
: [RuntimeGlobals.requireScope];
|
|
629
629
|
};
|
|
630
630
|
|
|
631
|
+
/**
|
|
632
|
+
* Prefixes an evaluation error with the offending define key so a bare
|
|
633
|
+
* "Unexpected token" becomes actionable. The original error is mutated and
|
|
634
|
+
* returned (not re-wrapped) so its `loc`/`stack` survive for ModuleParseError's
|
|
635
|
+
* code frame instead of being dumped into the message.
|
|
636
|
+
* @param {string} key the defined key
|
|
637
|
+
* @param {CodeValue} code the defined value
|
|
638
|
+
* @param {unknown} error the original evaluation error
|
|
639
|
+
* @returns {Error} the annotated error
|
|
640
|
+
*/
|
|
641
|
+
const annotateEvaluationError = (key, code, error) => {
|
|
642
|
+
const value = typeof code === "string" ? code : JSON.stringify(code);
|
|
643
|
+
const prefix = `DefinePlugin: failed to evaluate value for "${key}" (\`${value}\`)`;
|
|
644
|
+
if (error instanceof Error) {
|
|
645
|
+
error.message = `${prefix}: ${error.message}`;
|
|
646
|
+
return error;
|
|
647
|
+
}
|
|
648
|
+
return new WebpackError(`${prefix}: ${error}`);
|
|
649
|
+
};
|
|
650
|
+
|
|
631
651
|
/**
|
|
632
652
|
* Defines the define plugin hooks type used by this module.
|
|
633
653
|
* @typedef {object} DefinePluginHooks
|
|
@@ -954,17 +974,23 @@ class DefinePlugin {
|
|
|
954
974
|
});
|
|
955
975
|
parser.hooks.typeof.for(key).tap(PLUGIN_NAME, (expr) => {
|
|
956
976
|
addValueDependency(originalKey);
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
977
|
+
/** @type {BasicEvaluatedExpression} */
|
|
978
|
+
let res;
|
|
979
|
+
try {
|
|
980
|
+
const codeCode = toCode(
|
|
981
|
+
code,
|
|
982
|
+
parser,
|
|
983
|
+
compilation.valueCacheVersions,
|
|
984
|
+
originalKey,
|
|
985
|
+
runtimeTemplate,
|
|
986
|
+
logger,
|
|
987
|
+
null
|
|
988
|
+
);
|
|
989
|
+
const typeofCode = isTypeof ? codeCode : `typeof (${codeCode})`;
|
|
990
|
+
res = parser.evaluate(typeofCode);
|
|
991
|
+
} catch (err) {
|
|
992
|
+
throw annotateEvaluationError(originalKey, code, err);
|
|
993
|
+
}
|
|
968
994
|
if (!res.isString()) return;
|
|
969
995
|
return toConstantDependency(
|
|
970
996
|
parser,
|
package/lib/ExportsInfo.js
CHANGED
|
@@ -66,6 +66,11 @@ const UsageState = Object.freeze({
|
|
|
66
66
|
|
|
67
67
|
const RETURNS_TRUE = () => true;
|
|
68
68
|
|
|
69
|
+
// Shared empty visited-set for `findTarget`: `_findTarget` only reads
|
|
70
|
+
// `alreadyVisited` (`.has`), never mutates it, so a fresh `new Set()` per call
|
|
71
|
+
// is pure churn on the per-export reexport hot path. Must stay never-mutated.
|
|
72
|
+
const EMPTY_VISITED = /** @type {Set<ExportInfo>} */ (new Set());
|
|
73
|
+
|
|
69
74
|
const CIRCULAR = Symbol("circular target");
|
|
70
75
|
|
|
71
76
|
// bit layout of ExportInfo._inlineFlags
|
|
@@ -1399,12 +1404,16 @@ class ExportInfo {
|
|
|
1399
1404
|
* @returns {boolean} true, if something has changed
|
|
1400
1405
|
*/
|
|
1401
1406
|
setTarget(key, connection, exportName, priority = 0) {
|
|
1402
|
-
|
|
1407
|
+
// `equals` compares element-wise, so the incoming `exportName` can be used
|
|
1408
|
+
// directly for the change-check; only copy it when actually stored, so the
|
|
1409
|
+
// common no-op (unchanged target) path allocates nothing.
|
|
1403
1410
|
if (!this._target) {
|
|
1404
1411
|
this._target = /** @type {Target} */ (new Map());
|
|
1405
1412
|
this._target.set(key, {
|
|
1406
1413
|
connection,
|
|
1407
|
-
export: /** @type {ExportInfoName[]} */ (
|
|
1414
|
+
export: /** @type {ExportInfoName[]} */ (
|
|
1415
|
+
exportName ? [...exportName] : exportName
|
|
1416
|
+
),
|
|
1408
1417
|
priority
|
|
1409
1418
|
});
|
|
1410
1419
|
return true;
|
|
@@ -1414,7 +1423,9 @@ class ExportInfo {
|
|
|
1414
1423
|
if (oldTarget === null && !connection) return false;
|
|
1415
1424
|
this._target.set(key, {
|
|
1416
1425
|
connection,
|
|
1417
|
-
export: /** @type {ExportInfoName[]} */ (
|
|
1426
|
+
export: /** @type {ExportInfoName[]} */ (
|
|
1427
|
+
exportName ? [...exportName] : exportName
|
|
1428
|
+
),
|
|
1418
1429
|
priority
|
|
1419
1430
|
});
|
|
1420
1431
|
this._maxTarget = undefined;
|
|
@@ -1428,7 +1439,9 @@ class ExportInfo {
|
|
|
1428
1439
|
: oldTarget.export)
|
|
1429
1440
|
) {
|
|
1430
1441
|
oldTarget.connection = connection;
|
|
1431
|
-
oldTarget.export = /** @type {ExportInfoName[]} */ (
|
|
1442
|
+
oldTarget.export = /** @type {ExportInfoName[]} */ (
|
|
1443
|
+
exportName ? [...exportName] : exportName
|
|
1444
|
+
);
|
|
1432
1445
|
oldTarget.priority = priority;
|
|
1433
1446
|
this._maxTarget = undefined;
|
|
1434
1447
|
return true;
|
|
@@ -1578,7 +1591,11 @@ class ExportInfo {
|
|
|
1578
1591
|
* @returns {TargetItemWithoutConnection | null | undefined | false} the target, undefined when there is no target, false when no target is valid
|
|
1579
1592
|
*/
|
|
1580
1593
|
findTarget(moduleGraph, validTargetModuleFilter) {
|
|
1581
|
-
return this._findTarget(
|
|
1594
|
+
return this._findTarget(
|
|
1595
|
+
moduleGraph,
|
|
1596
|
+
validTargetModuleFilter,
|
|
1597
|
+
EMPTY_VISITED
|
|
1598
|
+
);
|
|
1582
1599
|
}
|
|
1583
1600
|
|
|
1584
1601
|
/**
|
package/lib/FileSystemInfo.js
CHANGED
|
@@ -297,6 +297,22 @@ class SnapshotIterable {
|
|
|
297
297
|
/** @typedef {Set<string>} ManagedMissing */
|
|
298
298
|
/** @typedef {Set<Snapshot>} Children */
|
|
299
299
|
|
|
300
|
+
// `Snapshot._flags` bit for each optional field. Serialized as a whole integer,
|
|
301
|
+
// so these values are a persisted-cache format contract — never renumber them.
|
|
302
|
+
const SNAPSHOT_FLAG_START_TIME = 1;
|
|
303
|
+
const SNAPSHOT_FLAG_FILE_TIMESTAMPS = 2;
|
|
304
|
+
const SNAPSHOT_FLAG_FILE_HASHES = 4;
|
|
305
|
+
const SNAPSHOT_FLAG_FILE_TSHS = 8;
|
|
306
|
+
const SNAPSHOT_FLAG_CONTEXT_TIMESTAMPS = 0x10;
|
|
307
|
+
const SNAPSHOT_FLAG_CONTEXT_HASHES = 0x20;
|
|
308
|
+
const SNAPSHOT_FLAG_CONTEXT_TSHS = 0x40;
|
|
309
|
+
const SNAPSHOT_FLAG_MISSING_EXISTENCE = 0x80;
|
|
310
|
+
const SNAPSHOT_FLAG_MANAGED_ITEM_INFO = 0x100;
|
|
311
|
+
const SNAPSHOT_FLAG_MANAGED_FILES = 0x200;
|
|
312
|
+
const SNAPSHOT_FLAG_MANAGED_CONTEXTS = 0x400;
|
|
313
|
+
const SNAPSHOT_FLAG_MANAGED_MISSING = 0x800;
|
|
314
|
+
const SNAPSHOT_FLAG_CHILDREN = 0x1000;
|
|
315
|
+
|
|
300
316
|
class Snapshot {
|
|
301
317
|
constructor() {
|
|
302
318
|
/** @type {number} */
|
|
@@ -336,7 +352,7 @@ class Snapshot {
|
|
|
336
352
|
}
|
|
337
353
|
|
|
338
354
|
hasStartTime() {
|
|
339
|
-
return (this._flags &
|
|
355
|
+
return (this._flags & SNAPSHOT_FLAG_START_TIME) !== 0;
|
|
340
356
|
}
|
|
341
357
|
|
|
342
358
|
/**
|
|
@@ -344,7 +360,7 @@ class Snapshot {
|
|
|
344
360
|
* @param {number} value start value
|
|
345
361
|
*/
|
|
346
362
|
setStartTime(value) {
|
|
347
|
-
this._flags |=
|
|
363
|
+
this._flags |= SNAPSHOT_FLAG_START_TIME;
|
|
348
364
|
this.startTime = value;
|
|
349
365
|
}
|
|
350
366
|
|
|
@@ -375,7 +391,7 @@ class Snapshot {
|
|
|
375
391
|
}
|
|
376
392
|
|
|
377
393
|
hasFileTimestamps() {
|
|
378
|
-
return (this._flags &
|
|
394
|
+
return (this._flags & SNAPSHOT_FLAG_FILE_TIMESTAMPS) !== 0;
|
|
379
395
|
}
|
|
380
396
|
|
|
381
397
|
/**
|
|
@@ -383,12 +399,12 @@ class Snapshot {
|
|
|
383
399
|
* @param {FileTimestamps} value file timestamps
|
|
384
400
|
*/
|
|
385
401
|
setFileTimestamps(value) {
|
|
386
|
-
this._flags |=
|
|
402
|
+
this._flags |= SNAPSHOT_FLAG_FILE_TIMESTAMPS;
|
|
387
403
|
this.fileTimestamps = value;
|
|
388
404
|
}
|
|
389
405
|
|
|
390
406
|
hasFileHashes() {
|
|
391
|
-
return (this._flags &
|
|
407
|
+
return (this._flags & SNAPSHOT_FLAG_FILE_HASHES) !== 0;
|
|
392
408
|
}
|
|
393
409
|
|
|
394
410
|
/**
|
|
@@ -396,12 +412,12 @@ class Snapshot {
|
|
|
396
412
|
* @param {FileHashes} value file hashes
|
|
397
413
|
*/
|
|
398
414
|
setFileHashes(value) {
|
|
399
|
-
this._flags |=
|
|
415
|
+
this._flags |= SNAPSHOT_FLAG_FILE_HASHES;
|
|
400
416
|
this.fileHashes = value;
|
|
401
417
|
}
|
|
402
418
|
|
|
403
419
|
hasFileTshs() {
|
|
404
|
-
return (this._flags &
|
|
420
|
+
return (this._flags & SNAPSHOT_FLAG_FILE_TSHS) !== 0;
|
|
405
421
|
}
|
|
406
422
|
|
|
407
423
|
/**
|
|
@@ -409,12 +425,12 @@ class Snapshot {
|
|
|
409
425
|
* @param {FileTshs} value file tshs
|
|
410
426
|
*/
|
|
411
427
|
setFileTshs(value) {
|
|
412
|
-
this._flags |=
|
|
428
|
+
this._flags |= SNAPSHOT_FLAG_FILE_TSHS;
|
|
413
429
|
this.fileTshs = value;
|
|
414
430
|
}
|
|
415
431
|
|
|
416
432
|
hasContextTimestamps() {
|
|
417
|
-
return (this._flags &
|
|
433
|
+
return (this._flags & SNAPSHOT_FLAG_CONTEXT_TIMESTAMPS) !== 0;
|
|
418
434
|
}
|
|
419
435
|
|
|
420
436
|
/**
|
|
@@ -422,12 +438,12 @@ class Snapshot {
|
|
|
422
438
|
* @param {ContextTimestamps} value context timestamps
|
|
423
439
|
*/
|
|
424
440
|
setContextTimestamps(value) {
|
|
425
|
-
this._flags |=
|
|
441
|
+
this._flags |= SNAPSHOT_FLAG_CONTEXT_TIMESTAMPS;
|
|
426
442
|
this.contextTimestamps = value;
|
|
427
443
|
}
|
|
428
444
|
|
|
429
445
|
hasContextHashes() {
|
|
430
|
-
return (this._flags &
|
|
446
|
+
return (this._flags & SNAPSHOT_FLAG_CONTEXT_HASHES) !== 0;
|
|
431
447
|
}
|
|
432
448
|
|
|
433
449
|
/**
|
|
@@ -435,12 +451,12 @@ class Snapshot {
|
|
|
435
451
|
* @param {ContextHashes} value context hashes
|
|
436
452
|
*/
|
|
437
453
|
setContextHashes(value) {
|
|
438
|
-
this._flags |=
|
|
454
|
+
this._flags |= SNAPSHOT_FLAG_CONTEXT_HASHES;
|
|
439
455
|
this.contextHashes = value;
|
|
440
456
|
}
|
|
441
457
|
|
|
442
458
|
hasContextTshs() {
|
|
443
|
-
return (this._flags &
|
|
459
|
+
return (this._flags & SNAPSHOT_FLAG_CONTEXT_TSHS) !== 0;
|
|
444
460
|
}
|
|
445
461
|
|
|
446
462
|
/**
|
|
@@ -448,12 +464,12 @@ class Snapshot {
|
|
|
448
464
|
* @param {ContextTshs} value context tshs
|
|
449
465
|
*/
|
|
450
466
|
setContextTshs(value) {
|
|
451
|
-
this._flags |=
|
|
467
|
+
this._flags |= SNAPSHOT_FLAG_CONTEXT_TSHS;
|
|
452
468
|
this.contextTshs = value;
|
|
453
469
|
}
|
|
454
470
|
|
|
455
471
|
hasMissingExistence() {
|
|
456
|
-
return (this._flags &
|
|
472
|
+
return (this._flags & SNAPSHOT_FLAG_MISSING_EXISTENCE) !== 0;
|
|
457
473
|
}
|
|
458
474
|
|
|
459
475
|
/**
|
|
@@ -461,12 +477,12 @@ class Snapshot {
|
|
|
461
477
|
* @param {MissingExistence} value context tshs
|
|
462
478
|
*/
|
|
463
479
|
setMissingExistence(value) {
|
|
464
|
-
this._flags |=
|
|
480
|
+
this._flags |= SNAPSHOT_FLAG_MISSING_EXISTENCE;
|
|
465
481
|
this.missingExistence = value;
|
|
466
482
|
}
|
|
467
483
|
|
|
468
484
|
hasManagedItemInfo() {
|
|
469
|
-
return (this._flags &
|
|
485
|
+
return (this._flags & SNAPSHOT_FLAG_MANAGED_ITEM_INFO) !== 0;
|
|
470
486
|
}
|
|
471
487
|
|
|
472
488
|
/**
|
|
@@ -474,12 +490,12 @@ class Snapshot {
|
|
|
474
490
|
* @param {ManagedItemInfo} value managed item info
|
|
475
491
|
*/
|
|
476
492
|
setManagedItemInfo(value) {
|
|
477
|
-
this._flags |=
|
|
493
|
+
this._flags |= SNAPSHOT_FLAG_MANAGED_ITEM_INFO;
|
|
478
494
|
this.managedItemInfo = value;
|
|
479
495
|
}
|
|
480
496
|
|
|
481
497
|
hasManagedFiles() {
|
|
482
|
-
return (this._flags &
|
|
498
|
+
return (this._flags & SNAPSHOT_FLAG_MANAGED_FILES) !== 0;
|
|
483
499
|
}
|
|
484
500
|
|
|
485
501
|
/**
|
|
@@ -487,12 +503,12 @@ class Snapshot {
|
|
|
487
503
|
* @param {ManagedFiles} value managed files
|
|
488
504
|
*/
|
|
489
505
|
setManagedFiles(value) {
|
|
490
|
-
this._flags |=
|
|
506
|
+
this._flags |= SNAPSHOT_FLAG_MANAGED_FILES;
|
|
491
507
|
this.managedFiles = value;
|
|
492
508
|
}
|
|
493
509
|
|
|
494
510
|
hasManagedContexts() {
|
|
495
|
-
return (this._flags &
|
|
511
|
+
return (this._flags & SNAPSHOT_FLAG_MANAGED_CONTEXTS) !== 0;
|
|
496
512
|
}
|
|
497
513
|
|
|
498
514
|
/**
|
|
@@ -500,12 +516,12 @@ class Snapshot {
|
|
|
500
516
|
* @param {ManagedContexts} value managed contexts
|
|
501
517
|
*/
|
|
502
518
|
setManagedContexts(value) {
|
|
503
|
-
this._flags |=
|
|
519
|
+
this._flags |= SNAPSHOT_FLAG_MANAGED_CONTEXTS;
|
|
504
520
|
this.managedContexts = value;
|
|
505
521
|
}
|
|
506
522
|
|
|
507
523
|
hasManagedMissing() {
|
|
508
|
-
return (this._flags &
|
|
524
|
+
return (this._flags & SNAPSHOT_FLAG_MANAGED_MISSING) !== 0;
|
|
509
525
|
}
|
|
510
526
|
|
|
511
527
|
/**
|
|
@@ -513,12 +529,12 @@ class Snapshot {
|
|
|
513
529
|
* @param {ManagedMissing} value managed missing
|
|
514
530
|
*/
|
|
515
531
|
setManagedMissing(value) {
|
|
516
|
-
this._flags |=
|
|
532
|
+
this._flags |= SNAPSHOT_FLAG_MANAGED_MISSING;
|
|
517
533
|
this.managedMissing = value;
|
|
518
534
|
}
|
|
519
535
|
|
|
520
536
|
hasChildren() {
|
|
521
|
-
return (this._flags &
|
|
537
|
+
return (this._flags & SNAPSHOT_FLAG_CHILDREN) !== 0;
|
|
522
538
|
}
|
|
523
539
|
|
|
524
540
|
/**
|
|
@@ -526,7 +542,7 @@ class Snapshot {
|
|
|
526
542
|
* @param {Children} value children
|
|
527
543
|
*/
|
|
528
544
|
setChildren(value) {
|
|
529
|
-
this._flags |=
|
|
545
|
+
this._flags |= SNAPSHOT_FLAG_CHILDREN;
|
|
530
546
|
this.children = value;
|
|
531
547
|
}
|
|
532
548
|
|
|
@@ -1221,6 +1237,58 @@ const addAll = (source, target) => {
|
|
|
1221
1237
|
|
|
1222
1238
|
const getEsModuleLexer = memoize(() => require("es-module-lexer"));
|
|
1223
1239
|
|
|
1240
|
+
const getAcorn = memoize(/* istanbul ignore next */ () => require("acorn"));
|
|
1241
|
+
|
|
1242
|
+
// Bun doesn't populate `require.cache` `module.children`, so the CJS build-dependency
|
|
1243
|
+
// walk needs a source-parsing fallback there. Node/Deno populate it — never pay for it.
|
|
1244
|
+
const IS_BUN = Boolean(process.versions.bun);
|
|
1245
|
+
|
|
1246
|
+
/**
|
|
1247
|
+
* Collects static `require("literal")` specifiers from CommonJS source. Used as a
|
|
1248
|
+
* fallback where `require.cache` children aren't populated (e.g. Bun), so build
|
|
1249
|
+
* dependencies of a CJS file are still tracked. Dynamic requires can't be seen here.
|
|
1250
|
+
* @param {string} source source
|
|
1251
|
+
* @returns {Set<string>} required specifiers
|
|
1252
|
+
*/
|
|
1253
|
+
// Bun-only: exercised by BuildDependencies.longtest under the Bun CI job (no coverage upload).
|
|
1254
|
+
/* istanbul ignore next */
|
|
1255
|
+
const parseCjsRequires = (source) => {
|
|
1256
|
+
/** @type {Set<string>} */
|
|
1257
|
+
const requires = new Set();
|
|
1258
|
+
const ast = getAcorn().parse(source, {
|
|
1259
|
+
ecmaVersion: "latest",
|
|
1260
|
+
sourceType: "script",
|
|
1261
|
+
allowReturnOutsideFunction: true
|
|
1262
|
+
});
|
|
1263
|
+
/** @type {EXPECTED_ANY[]} */
|
|
1264
|
+
const stack = [ast];
|
|
1265
|
+
while (stack.length > 0) {
|
|
1266
|
+
const node = stack.pop();
|
|
1267
|
+
if (!node || typeof node.type !== "string") continue;
|
|
1268
|
+
if (
|
|
1269
|
+
node.type === "CallExpression" &&
|
|
1270
|
+
node.callee.type === "Identifier" &&
|
|
1271
|
+
node.callee.name === "require" &&
|
|
1272
|
+
node.arguments.length === 1 &&
|
|
1273
|
+
node.arguments[0].type === "Literal" &&
|
|
1274
|
+
typeof node.arguments[0].value === "string"
|
|
1275
|
+
) {
|
|
1276
|
+
requires.add(node.arguments[0].value);
|
|
1277
|
+
}
|
|
1278
|
+
for (const key of Object.keys(node)) {
|
|
1279
|
+
const value = node[key];
|
|
1280
|
+
if (Array.isArray(value)) {
|
|
1281
|
+
for (const item of value) {
|
|
1282
|
+
if (item && typeof item.type === "string") stack.push(item);
|
|
1283
|
+
}
|
|
1284
|
+
} else if (value && typeof value.type === "string") {
|
|
1285
|
+
stack.push(value);
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
return requires;
|
|
1290
|
+
};
|
|
1291
|
+
|
|
1224
1292
|
/** @typedef {Set<string>} LoggedPaths */
|
|
1225
1293
|
|
|
1226
1294
|
/** @typedef {FileSystemInfoEntry | ExistenceOnlyTimeEntry | "ignore" | null} FileTimestamp */
|
|
@@ -2213,6 +2281,38 @@ class FileSystemInfo {
|
|
|
2213
2281
|
});
|
|
2214
2282
|
}
|
|
2215
2283
|
}
|
|
2284
|
+
// On Bun the children array is empty (unpopulated), so recover the
|
|
2285
|
+
// static require() specifiers by parsing the source; Node/Deno don't.
|
|
2286
|
+
/* istanbul ignore next */
|
|
2287
|
+
if (IS_BUN && module.children.length === 0) {
|
|
2288
|
+
this.fs.readFile(path, (err, content) => {
|
|
2289
|
+
if (err) return callback(err);
|
|
2290
|
+
try {
|
|
2291
|
+
const context = dirname(this.fs, path);
|
|
2292
|
+
const source = /** @type {Buffer} */ (content).toString();
|
|
2293
|
+
/** @type {Set<string>} */
|
|
2294
|
+
const added = new Set();
|
|
2295
|
+
for (const dependency of parseCjsRequires(source)) {
|
|
2296
|
+
if (dependency.startsWith("node:")) continue;
|
|
2297
|
+
if (builtinModules.has(dependency)) continue;
|
|
2298
|
+
if (added.has(dependency)) continue;
|
|
2299
|
+
push({
|
|
2300
|
+
type: RBDT_RESOLVE_CJS_FILE,
|
|
2301
|
+
context,
|
|
2302
|
+
path: dependency,
|
|
2303
|
+
// Best effort: tolerate specifiers that don't resolve.
|
|
2304
|
+
expected: false,
|
|
2305
|
+
issuer: job
|
|
2306
|
+
});
|
|
2307
|
+
added.add(dependency);
|
|
2308
|
+
}
|
|
2309
|
+
} catch (_err) {
|
|
2310
|
+
// Source we can't parse as CommonJS — ignore its dependencies.
|
|
2311
|
+
}
|
|
2312
|
+
process.nextTick(callback);
|
|
2313
|
+
});
|
|
2314
|
+
break;
|
|
2315
|
+
}
|
|
2216
2316
|
} else if (supportsEsm && /\.m?js$/.test(path)) {
|
|
2217
2317
|
if (!this._warnAboutExperimentalEsmTracking) {
|
|
2218
2318
|
logger.log(
|
|
@@ -30,6 +30,19 @@ const {
|
|
|
30
30
|
const PLUGIN_NAME = "FlagDependencyUsagePlugin";
|
|
31
31
|
const PLUGIN_LOGGER_NAME = `webpack.${PLUGIN_NAME}`;
|
|
32
32
|
|
|
33
|
+
// Hoisted stateless predicates for setUsedConditionally on the innermost
|
|
34
|
+
// used-export loop, so they aren't re-allocated per export.
|
|
35
|
+
/**
|
|
36
|
+
* @param {import("./ExportsInfo").UsageStateType} used usage state
|
|
37
|
+
* @returns {boolean} whether unused
|
|
38
|
+
*/
|
|
39
|
+
const IS_UNUSED = (used) => used === UsageState.Unused;
|
|
40
|
+
/**
|
|
41
|
+
* @param {import("./ExportsInfo").UsageStateType} used usage state
|
|
42
|
+
* @returns {boolean} whether not used
|
|
43
|
+
*/
|
|
44
|
+
const IS_NOT_USED = (used) => used !== UsageState.Used;
|
|
45
|
+
|
|
33
46
|
class FlagDependencyUsagePlugin {
|
|
34
47
|
/**
|
|
35
48
|
* Creates an instance of FlagDependencyUsagePlugin.
|
|
@@ -162,7 +175,7 @@ class FlagDependencyUsagePlugin {
|
|
|
162
175
|
if (nestedInfo) {
|
|
163
176
|
if (
|
|
164
177
|
exportInfo.setUsedConditionally(
|
|
165
|
-
|
|
178
|
+
IS_UNUSED,
|
|
166
179
|
UsageState.OnlyPropertiesUsed,
|
|
167
180
|
runtime
|
|
168
181
|
)
|
|
@@ -181,7 +194,7 @@ class FlagDependencyUsagePlugin {
|
|
|
181
194
|
}
|
|
182
195
|
if (
|
|
183
196
|
exportInfo.setUsedConditionally(
|
|
184
|
-
|
|
197
|
+
IS_NOT_USED,
|
|
185
198
|
UsageState.Used,
|
|
186
199
|
runtime
|
|
187
200
|
)
|
|
@@ -229,8 +242,9 @@ class FlagDependencyUsagePlugin {
|
|
|
229
242
|
// Modules whose whole namespace object escapes in a mangleable way.
|
|
230
243
|
// Tracked separately so specific member references are still merged
|
|
231
244
|
// (and marked used) instead of being dropped by the escape marker.
|
|
232
|
-
|
|
233
|
-
|
|
245
|
+
// Lazily allocated — usually empty.
|
|
246
|
+
/** @type {Set<Module> | undefined} */
|
|
247
|
+
let mangleableEscapeModules;
|
|
234
248
|
|
|
235
249
|
/** @type {ArrayQueue<DependenciesBlock>} */
|
|
236
250
|
const queue = new ArrayQueue();
|
|
@@ -273,7 +287,9 @@ class FlagDependencyUsagePlugin {
|
|
|
273
287
|
// conservative result and always wins.
|
|
274
288
|
if (referencedExports === EXPORTS_OBJECT_REFERENCED) {
|
|
275
289
|
map.set(module, EXPORTS_OBJECT_REFERENCED);
|
|
276
|
-
mangleableEscapeModules
|
|
290
|
+
if (mangleableEscapeModules) {
|
|
291
|
+
mangleableEscapeModules.delete(module);
|
|
292
|
+
}
|
|
277
293
|
continue;
|
|
278
294
|
}
|
|
279
295
|
// A mangleable whole-object escape keeps the module's exports
|
|
@@ -284,6 +300,9 @@ class FlagDependencyUsagePlugin {
|
|
|
284
300
|
if (
|
|
285
301
|
referencedExports === EXPORTS_OBJECT_REFERENCED_MANGLEABLE
|
|
286
302
|
) {
|
|
303
|
+
if (mangleableEscapeModules === undefined) {
|
|
304
|
+
mangleableEscapeModules = new Set();
|
|
305
|
+
}
|
|
287
306
|
mangleableEscapeModules.add(module);
|
|
288
307
|
continue;
|
|
289
308
|
}
|
|
@@ -358,13 +377,15 @@ class FlagDependencyUsagePlugin {
|
|
|
358
377
|
);
|
|
359
378
|
}
|
|
360
379
|
}
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
380
|
+
if (mangleableEscapeModules) {
|
|
381
|
+
for (const module of mangleableEscapeModules) {
|
|
382
|
+
processReferencedModule(
|
|
383
|
+
module,
|
|
384
|
+
EXPORTS_OBJECT_REFERENCED_MANGLEABLE,
|
|
385
|
+
runtime,
|
|
386
|
+
forceSideEffects
|
|
387
|
+
);
|
|
388
|
+
}
|
|
368
389
|
}
|
|
369
390
|
};
|
|
370
391
|
|