Skip to content

Commit 0fd96ac

Browse files
authored
Merge pull request #14735 from webpack/bugfix/unsafe-cache-managed-paths
fix unsafeCache with managedPaths
2 parents a2e4d20 + cae22d1 commit 0fd96ac

File tree

25 files changed

+203
-30
lines changed

25 files changed

+203
-30
lines changed

lib/FileSystemInfo.js

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2016,8 +2016,7 @@ class FileSystemInfo {
20162016
}
20172017
return capturedItems;
20182018
};
2019-
if (files) {
2020-
const capturedFiles = captureNonManaged(files, managedFiles);
2019+
const processCapturedFiles = capturedFiles => {
20212020
switch (mode) {
20222021
case 3:
20232022
this._fileTshsOptimization.optimize(snapshot, capturedFiles);
@@ -2094,12 +2093,11 @@ class FileSystemInfo {
20942093
}
20952094
break;
20962095
}
2096+
};
2097+
if (files) {
2098+
processCapturedFiles(captureNonManaged(files, managedFiles));
20972099
}
2098-
if (directories) {
2099-
const capturedDirectories = captureNonManaged(
2100-
directories,
2101-
managedContexts
2102-
);
2100+
const processCapturedDirectories = capturedDirectories => {
21032101
switch (mode) {
21042102
case 3:
21052103
this._contextTshsOptimization.optimize(snapshot, capturedDirectories);
@@ -2219,9 +2217,13 @@ class FileSystemInfo {
22192217
}
22202218
break;
22212219
}
2220+
};
2221+
if (directories) {
2222+
processCapturedDirectories(
2223+
captureNonManaged(directories, managedContexts)
2224+
);
22222225
}
2223-
if (missing) {
2224-
const capturedMissing = captureNonManaged(missing, managedMissing);
2226+
const processCapturedMissing = capturedMissing => {
22252227
this._missingExistenceOptimization.optimize(snapshot, capturedMissing);
22262228
for (const path of capturedMissing) {
22272229
const cache = this._fileTimestamps.get(path);
@@ -2246,11 +2248,15 @@ class FileSystemInfo {
22462248
});
22472249
}
22482250
}
2251+
};
2252+
if (missing) {
2253+
processCapturedMissing(captureNonManaged(missing, managedMissing));
22492254
}
22502255
this._managedItemInfoOptimization.optimize(snapshot, managedItems);
22512256
for (const path of managedItems) {
22522257
const cache = this._managedItems.get(path);
22532258
if (cache !== undefined) {
2259+
managedFiles.add(join(this.fs, path, "package.json"));
22542260
managedItemInfo.set(path, cache);
22552261
} else {
22562262
jobs++;
@@ -2262,9 +2268,24 @@ class FileSystemInfo {
22622268
);
22632269
}
22642270
jobError();
2265-
} else {
2271+
} else if (entry) {
2272+
managedFiles.add(join(this.fs, path, "package.json"));
22662273
managedItemInfo.set(path, entry);
22672274
jobDone();
2275+
} else {
2276+
// Fallback to normal snapshotting
2277+
const process = (set, fn) => {
2278+
if (set.size === 0) return;
2279+
const captured = new Set();
2280+
for (const file of set) {
2281+
if (file.startsWith(path)) captured.add(file);
2282+
}
2283+
if (captured.size > 0) fn(captured);
2284+
};
2285+
process(managedFiles, processCapturedFiles);
2286+
process(managedContexts, processCapturedDirectories);
2287+
process(managedMissing, processCapturedMissing);
2288+
jobDone();
22682289
}
22692290
});
22702291
}
@@ -3477,9 +3498,10 @@ class FileSystemInfo {
34773498
this._managedItems.set(path, "nested");
34783499
return callback(null, "nested");
34793500
}
3480-
const problem = `Managed item ${path} isn't a directory or doesn't contain a package.json`;
3481-
this.logger.warn(problem);
3482-
return callback(new Error(problem));
3501+
this.logger.warn(
3502+
`Managed item ${path} isn't a directory or doesn't contain a package.json (see snapshot.managedPaths option)`
3503+
);
3504+
return callback();
34833505
});
34843506
return;
34853507
}
@@ -3491,6 +3513,12 @@ class FileSystemInfo {
34913513
} catch (e) {
34923514
return callback(e);
34933515
}
3516+
if (!data.name) {
3517+
this.logger.warn(
3518+
`${packageJsonPath} doesn't contain a "name" property (see snapshot.managedPaths option)`
3519+
);
3520+
return callback();
3521+
}
34943522
const info = `${data.name || ""}@${data.version || ""}`;
34953523
this._managedItems.set(path, info);
34963524
callback(null, info);

test/BuildDependencies.longtest.js

Lines changed: 70 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,49 @@ const exec = (n, options = {}) => {
3939
p.stderr.on("data", chunk => chunks.push(chunk));
4040
p.stdout.on("data", chunk => chunks.push(chunk));
4141
p.once("exit", code => {
42-
const stdout = chunks.join("");
42+
const errors = [];
43+
const warnings = [];
44+
const rawStdout = chunks.join("");
45+
const stdout = rawStdout.replace(
46+
// This warning is expected
47+
/<([ew])> \[.+\n(?:<([ew])> [^[].+\n)*/g,
48+
(message, type) => {
49+
(type === "e" ? errors : warnings).push(message);
50+
return "";
51+
}
52+
);
53+
if (errors.length > 0) {
54+
return reject(
55+
new Error(
56+
`Unexpected errors in ${n} output:\n${errors.join(
57+
"\n"
58+
)}\n\n${rawStdout}`
59+
)
60+
);
61+
}
62+
for (const regexp of options.warnings || []) {
63+
const idx = warnings.findIndex(w => regexp.test(w));
64+
if (idx < 0) {
65+
return reject(
66+
new Error(
67+
`Warning ${regexp} was not found in ${n} output:\n${rawStdout}`
68+
)
69+
);
70+
}
71+
warnings.splice(idx, 1);
72+
}
73+
if (warnings.length > 0) {
74+
return reject(
75+
new Error(
76+
`Unexpected warnings in ${n} output:\n${warnings.join(
77+
"\n"
78+
)}\n\n${rawStdout}`
79+
)
80+
);
81+
}
4382
if (code === 0) {
4483
if (!options.ignoreErrors && /<[ew]>/.test(stdout))
45-
return reject(stdout);
84+
return reject(new Error(stdout));
4685
resolve(stdout);
4786
} else {
4887
reject(new Error(`Code ${code}: ${stdout}`));
@@ -99,7 +138,7 @@ describe("BuildDependencies", () => {
99138
await exec("0", {
100139
invalidBuildDepdencies: true,
101140
buildTwice: true,
102-
ignoreErrors: true
141+
warnings: [/Can't resolve 'should-fail-resolving'/]
103142
});
104143
fs.writeFileSync(
105144
path.resolve(inputDirectory, "loader-dependency.js"),
@@ -113,13 +152,21 @@ describe("BuildDependencies", () => {
113152
path.resolve(inputDirectory, "esm-dependency.js"),
114153
"module.exports = 1;"
115154
);
116-
await exec("1");
155+
await exec("1", {
156+
warnings: supportsEsm && [
157+
/Managed item .+dep-without-package\.json isn't a directory or doesn't contain a package\.json/
158+
]
159+
});
117160
fs.writeFileSync(
118161
path.resolve(inputDirectory, "loader-dependency.js"),
119162
"module.exports = Date.now();"
120163
);
121164
const now1 = Date.now();
122-
const output2 = await exec("2");
165+
const output2 = await exec("2", {
166+
warnings: supportsEsm && [
167+
/Managed item .+dep-without-package\.json isn't a directory or doesn't contain a package\.json/
168+
]
169+
});
123170
expect(output2).toMatch(/but build dependencies have changed/);
124171
expect(output2).toMatch(/Captured build dependencies/);
125172
expect(output2).not.toMatch(/Assuming/);
@@ -137,7 +184,11 @@ describe("BuildDependencies", () => {
137184
version: "2.0.0"
138185
})
139186
);
140-
const output4 = await exec("4");
187+
const output4 = await exec("4", {
188+
warnings: supportsEsm && [
189+
/Managed item .+dep-without-package\.json isn't a directory or doesn't contain a package\.json/
190+
]
191+
});
141192
expect(output4).toMatch(/resolving of build dependencies is invalid/);
142193
expect(output4).not.toMatch(/but build dependencies have changed/);
143194
expect(output4).toMatch(/Captured build dependencies/);
@@ -146,7 +197,11 @@ describe("BuildDependencies", () => {
146197
"module.exports = Date.now();"
147198
);
148199
const now2 = Date.now();
149-
await exec("5");
200+
await exec("5", {
201+
warnings: supportsEsm && [
202+
/Managed item .+dep-without-package\.json isn't a directory or doesn't contain a package\.json/
203+
]
204+
});
150205
const now3 = Date.now();
151206
await exec("6");
152207
await exec("7", {
@@ -160,7 +215,10 @@ describe("BuildDependencies", () => {
160215
);
161216
now4 = Date.now();
162217
await exec("8", {
163-
definedValue: "other"
218+
definedValue: "other",
219+
warnings: [
220+
/Managed item .+dep-without-package\.json isn't a directory or doesn't contain a package\.json/
221+
]
164222
});
165223
fs.writeFileSync(
166224
path.resolve(inputDirectory, "esm-async-dependency.mjs"),
@@ -169,7 +227,10 @@ describe("BuildDependencies", () => {
169227
now5 = Date.now();
170228

171229
await exec("9", {
172-
definedValue: "other"
230+
definedValue: "other",
231+
warnings: [
232+
/Managed item .+dep-without-package\.json isn't a directory or doesn't contain a package\.json/
233+
]
173234
});
174235
}
175236
const results = Array.from({ length: supportsEsm ? 10 : 8 }).map((_, i) =>

test/ConfigCacheTestCases.longtest.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
const path = require("path");
21
const { describeCases } = require("./ConfigTestCases.template");
32

43
describeCases({
@@ -8,8 +7,5 @@ describeCases({
87
buildDependencies: {
98
defaultWebpack: []
109
}
11-
},
12-
snapshot: {
13-
managedPaths: [path.resolve(__dirname, "../node_modules")]
1410
}
1511
});

test/ConfigTestCases.template.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,11 @@ const describeCases = config => {
9898
...config.cache
9999
};
100100
}
101-
if (config.snapshot) {
102-
options.snapshot = {
103-
...config.snapshot
104-
};
101+
if (!options.snapshot) options.snapshot = {};
102+
if (!options.snapshot.managedPaths) {
103+
options.snapshot.managedPaths = [
104+
path.resolve(__dirname, "../node_modules")
105+
];
105106
}
106107
});
107108
testConfig = {

test/configCases/cache-dependencies/managed-items-unsafe-cache/extra.js

Whitespace-only changes.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import "./loader!package";
2+
3+
it("should compile and run the test in config", () => {});
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
const path = require("path");
2+
3+
/** @type {import("../../../../").LoaderDefinition} */
4+
module.exports = function (source) {
5+
this.addDependency(path.resolve(__dirname, "node_modules/package/extra.js"));
6+
this.addDependency(path.resolve(__dirname, "extra.js"));
7+
return source;
8+
};

test/configCases/cache-dependencies/managed-items-unsafe-cache/node_modules/package/extra.js

Whitespace-only changes.

test/configCases/cache-dependencies/managed-items-unsafe-cache/node_modules/package/index.js

Whitespace-only changes.

test/configCases/cache-dependencies/managed-items-unsafe-cache/node_modules/package/package.json

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy