Visitar URL original
feat(caching): allow optional filesystem cache build dependencies (#2… · webpack/webpack@a03c24a · GitHub
Skip to content

Commit a03c24a

Browse files
authored
feat(caching): allow optional filesystem cache build dependencies (#21849)
1 parent 556a35f commit a03c24a

22 files changed

Lines changed: 284 additions & 41 deletions
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"webpack": minor
3+
---
4+
5+
Allow optional filesystem cache build dependencies.

‎declarations/WebpackOptions.d.ts‎

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,22 @@ export type CacheOptions = true | CacheOptionsNormalized;
2525
*/
2626
export type CacheOptionsNormalized =
2727
false | MemoryCacheOptions | FileCacheOptions;
28+
/**
29+
* A build dependency for filesystem cache invalidation.
30+
* @since 5.111.0
31+
*/
32+
export type BuildDependencyItem =
33+
| string
34+
| {
35+
/**
36+
* Request to a dependency (resolved as directory relative to the context directory).
37+
*/
38+
dependency: string;
39+
/**
40+
* When true, the dependency may be missing. Existence changes invalidate the cache.
41+
*/
42+
optional?: boolean;
43+
};
2844
/**
2945
* The base directory (absolute path!) for resolving the `entry` option. If `output.pathinfo` is set, the included pathinfo is shortened to this directory.
3046
*/
@@ -1213,7 +1229,7 @@ export interface FileCacheOptions {
12131229
/**
12141230
* List of dependencies the build depends on.
12151231
*/
1216-
[k: string]: string[];
1232+
[k: string]: BuildDependencyItem[];
12171233
};
12181234
/**
12191235
* Base directory for the cache (defaults to node_modules/.cache/webpack).

‎lib/Cache.js‎

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,11 @@ class Cache {
7070
get: new AsyncSeriesBailHook(["identifier", "etag", "gotHandlers"]),
7171
/** @type {AsyncParallelHook<[string, Etag | null, Data]>} */
7272
store: new AsyncParallelHook(["identifier", "etag", "data"]),
73-
/** @type {AsyncParallelHook<[Iterable<string>]>} */
74-
storeBuildDependencies: new AsyncParallelHook(["dependencies"]),
73+
/** @type {AsyncParallelHook<[Iterable<string>, Iterable<string>]>} */
74+
storeBuildDependencies: new AsyncParallelHook([
75+
"dependencies",
76+
"optionalDependencies"
77+
]),
7578
/** @type {SyncHook<[]>} */
7679
beginIdle: new SyncHook([]),
7780
/** @type {AsyncParallelHook<[]>} */
@@ -139,12 +142,14 @@ class Cache {
139142
* Persists the set of build dependencies required to determine whether the
140143
* cache can be restored in a future compilation.
141144
* @param {Iterable<string>} dependencies list of all build dependencies
145+
* @param {Iterable<string>} optionalDependencies list of optional build dependencies
142146
* @param {CallbackCache<void>} callback signals when the dependencies are stored
143147
* @returns {void}
144148
*/
145-
storeBuildDependencies(dependencies, callback) {
149+
storeBuildDependencies(dependencies, optionalDependencies, callback) {
146150
this.hooks.storeBuildDependencies.callAsync(
147151
dependencies,
152+
optionalDependencies,
148153
makeWebpackErrorCallback(callback, "Cache.hooks.storeBuildDependencies")
149154
);
150155
}

‎lib/Compilation.js‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1458,6 +1458,8 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
14581458
this.missingDependencies = new LazySet();
14591459
/** @type {FileSystemDependencies} */
14601460
this.buildDependencies = new LazySet();
1461+
/** @type {FileSystemDependencies} */
1462+
this.optionalBuildDependencies = new LazySet();
14611463
// TODO webpack 6 remove
14621464
/**
14631465
* @deprecated
@@ -5008,6 +5010,7 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
50085010
this.contextDependencies.addAll(child.contextDependencies);
50095011
this.missingDependencies.addAll(child.missingDependencies);
50105012
this.buildDependencies.addAll(child.buildDependencies);
5013+
this.optionalBuildDependencies.addAll(child.optionalBuildDependencies);
50115014
}
50125015

50135016
for (const module of this.modules) {

‎lib/Compiler.js‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -671,6 +671,7 @@ class Compiler {
671671
if (err) return finalCallback(err);
672672
this.cache.storeBuildDependencies(
673673
compilation.buildDependencies,
674+
compilation.optionalBuildDependencies,
674675
(err) => {
675676
if (err) return finalCallback(err);
676677
return finalCallback(null, stats);

‎lib/FileSystemInfo.js‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1884,10 +1884,13 @@ class FileSystemInfo {
18841884
* Resolves build dependencies.
18851885
* @param {string} context context directory
18861886
* @param {Iterable<string>} deps dependencies
1887+
* @param {Iterable<string> | undefined} optionalDeps optional dependencies that may be missing
18871888
* @param {(err?: Error | null, resolveBuildDependenciesResult?: ResolveBuildDependenciesResult) => void} callback callback function
18881889
* @returns {void}
18891890
*/
1890-
resolveBuildDependencies(context, deps, callback) {
1891+
resolveBuildDependencies(context, deps, optionalDeps, callback) {
1892+
/** @type {Set<string>} */
1893+
const optional = new Set(optionalDeps);
18911894
const { resolveContext, resolveEsm, resolveCjs, resolveCjsAsChild } =
18921895
this._createBuildDependenciesResolvers();
18931896

@@ -1979,7 +1982,7 @@ class FileSystemInfo {
19791982
type: RBDT_RESOLVE_INITIAL,
19801983
context,
19811984
path: dep,
1982-
expected: undefined,
1985+
expected: optional.has(dep) ? false : undefined,
19831986
issuer: undefined
19841987
})
19851988
),
@@ -2005,6 +2008,7 @@ class FileSystemInfo {
20052008
if (err) {
20062009
if (expected === false) {
20072010
resolveResults.set(key, false);
2011+
resolveMissing.add(path);
20082012
return callback();
20092013
}
20102014
invalidResolveResults.add(key);
@@ -2060,6 +2064,7 @@ class FileSystemInfo {
20602064
if (err) {
20612065
if (expected === false) {
20622066
resolveResults.set(key, false);
2067+
resolveMissing.add(path);
20632068
return callback();
20642069
}
20652070
invalidResolveResults.add(key);

‎lib/Watching.js‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,7 @@ class Watching {
307307
logger.time("storeBuildDependencies");
308308
this.compiler.cache.storeBuildDependencies(
309309
compilation.buildDependencies,
310+
compilation.optionalBuildDependencies,
310311
(err) => {
311312
logger.timeEnd("storeBuildDependencies");
312313
if (err) return handleError(err);
@@ -338,6 +339,8 @@ class Watching {
338339
this.compiler.cache.storeBuildDependencies(
339340
/** @type {Compilation} */
340341
(compilation).buildDependencies,
342+
/** @type {Compilation} */
343+
(compilation).optionalBuildDependencies,
341344
(err) => {
342345
logger.timeEnd("storeBuildDependencies");
343346
if (err) return handleError(err, cbs);
@@ -518,6 +521,7 @@ class Watching {
518521
logger.time("storeBuildDependencies");
519522
this.compiler.cache.storeBuildDependencies(
520523
compilation.buildDependencies,
524+
compilation.optionalBuildDependencies,
521525
(err2) => {
522526
logger.timeEnd("storeBuildDependencies");
523527
shutdown(err || err2);

‎lib/cache/AddBuildDependenciesPlugin.js‎

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,36 @@
99

1010
const PLUGIN_NAME = "AddBuildDependenciesPlugin";
1111

12+
/**
13+
* @typedef {object} NormalizedBuildDependencyItem
14+
* @property {string} dependency request to resolve
15+
* @property {boolean} optional when true the dependency may be missing
16+
*/
17+
18+
/**
19+
* @param {string | { dependency: string, optional?: boolean }} item build dependency
20+
* @returns {NormalizedBuildDependencyItem} normalized build dependency
21+
*/
22+
const normalizeBuildDependencyItem = (item) => {
23+
if (typeof item === "string") {
24+
return { dependency: item, optional: false };
25+
}
26+
return {
27+
dependency: item.dependency,
28+
optional: Boolean(item.optional)
29+
};
30+
};
31+
1232
class AddBuildDependenciesPlugin {
1333
/**
1434
* Creates an instance of AddBuildDependenciesPlugin.
15-
* @param {Iterable<string>} buildDependencies list of build dependencies
35+
* @param {Iterable<string | { dependency: string, optional?: boolean }>} buildDependencies list of build dependencies
1636
*/
1737
constructor(buildDependencies) {
18-
/** @type {Set<string>} */
19-
this.buildDependencies = new Set(buildDependencies);
38+
/** @type {NormalizedBuildDependencyItem[]} */
39+
this.buildDependencies = [...buildDependencies].map(
40+
normalizeBuildDependencyItem
41+
);
2042
}
2143

2244
/**
@@ -26,7 +48,14 @@ class AddBuildDependenciesPlugin {
2648
*/
2749
apply(compiler) {
2850
compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
29-
compilation.buildDependencies.addAll(this.buildDependencies);
51+
for (const { dependency, optional } of this.buildDependencies) {
52+
compilation.buildDependencies.add(dependency);
53+
if (optional) {
54+
compilation.optionalBuildDependencies.add(dependency);
55+
compilation.missingDependencies.add(dependency);
56+
compilation.fileDependencies.add(dependency);
57+
}
58+
}
3059
});
3160
}
3261
}

‎lib/cache/IdleFileCachePlugin.js‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,10 @@ class IdleFileCachePlugin {
9898

9999
compiler.cache.hooks.storeBuildDependencies.tap(
100100
{ name: PLUGIN_NAME, stage: Cache.STAGE_DISK },
101-
(dependencies) => {
101+
(dependencies, optionalDependencies) => {
102102
pendingIdleTasks.set(BUILD_DEPENDENCIES_KEY, () =>
103103
Promise.resolve().then(() =>
104-
strategy.storeBuildDependencies(dependencies)
104+
strategy.storeBuildDependencies(dependencies, optionalDependencies)
105105
)
106106
);
107107
}

‎lib/cache/PackFileCacheStrategy.js‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1263,6 +1263,8 @@ class PackFileCacheStrategy {
12631263
this.buildDependencies = new Set();
12641264
/** @type {FileSystemDependencies} */
12651265
this.newBuildDependencies = new LazySet();
1266+
/** @type {FileSystemDependencies} */
1267+
this.newOptionalBuildDependencies = new LazySet();
12661268
/** @type {InstanceType<Snapshot> | undefined} */
12671269
this.resolveBuildDependenciesSnapshot = undefined;
12681270
/** @type {ResolveResults | undefined} */
@@ -1492,10 +1494,13 @@ class PackFileCacheStrategy {
14921494
/**
14931495
* Stores build dependencies.
14941496
* @param {FileSystemDependencies | Iterable<string>} dependencies dependencies to store
1497+
* @param {FileSystemDependencies | Iterable<string>} optionalDependencies optional dependencies to store
1498+
* @returns {void}
14951499
*/
1496-
storeBuildDependencies(dependencies) {
1500+
storeBuildDependencies(dependencies, optionalDependencies) {
14971501
if (this.readonly) return;
14981502
this.newBuildDependencies.addAll(dependencies);
1503+
this.newOptionalBuildDependencies.addAll(optionalDependencies);
14991504
}
15001505

15011506
afterAllStored() {
@@ -1512,9 +1517,14 @@ class PackFileCacheStrategy {
15121517
let promise;
15131518
/** @type {Set<string>} */
15141519
const newBuildDependencies = new Set();
1520+
/** @type {Set<string>} */
1521+
const optionalBuildDependencies = new Set();
15151522
for (const dep of this.newBuildDependencies) {
15161523
if (!this.buildDependencies.has(dep)) {
15171524
newBuildDependencies.add(dep);
1525+
if (this.newOptionalBuildDependencies.has(dep)) {
1526+
optionalBuildDependencies.add(dep);
1527+
}
15181528
}
15191529
}
15201530
if (newBuildDependencies.size > 0 || !this.buildSnapshot) {
@@ -1533,6 +1543,7 @@ class PackFileCacheStrategy {
15331543
this.fileSystemInfo.resolveBuildDependencies(
15341544
this.context,
15351545
newBuildDependencies,
1546+
optionalBuildDependencies,
15361547
(err, result) => {
15371548
this.logger.timeEnd("resolve build dependencies");
15381549
if (err) return reject(err);
@@ -1667,6 +1678,7 @@ class PackFileCacheStrategy {
16671678
this.buildDependencies.add(dep);
16681679
}
16691680
this.newBuildDependencies.clear();
1681+
this.newOptionalBuildDependencies.clear();
16701682
this.logger.timeEnd("store pack");
16711683
const stats = pack.getContentStats();
16721684
this.logger.log(
@@ -1887,6 +1899,7 @@ class PackFileCacheStrategy {
18871899
this.fileSystemInfo.clear();
18881900
this.buildDependencies.clear();
18891901
this.newBuildDependencies.clear();
1902+
this.newOptionalBuildDependencies.clear();
18901903
this.resolveBuildDependenciesSnapshot = undefined;
18911904
this.resolveResults = undefined;
18921905
this.buildSnapshot = undefined;

0 commit comments

Comments
 (0)