Skip to content

Commit cae22d1

Browse files
committed
fallback to normal snapshotting when managed path optimization fails
1 parent 98ea582 commit cae22d1

File tree

18 files changed

+177
-33
lines changed

18 files changed

+177
-33
lines changed

lib/FileSystemInfo.js

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1993,7 +1993,6 @@ class FileSystemInfo {
19931993
if (managedItem) {
19941994
managedItems.add(managedItem);
19951995
managedSet.add(path);
1996-
managedFiles.add(join(this.fs, managedItem, "package.json"));
19971996
return true;
19981997
}
19991998
}
@@ -2004,7 +2003,6 @@ class FileSystemInfo {
20042003
if (managedItem) {
20052004
managedItems.add(managedItem);
20062005
managedSet.add(path);
2007-
managedFiles.add(join(this.fs, managedItem, "package.json"));
20082006
return true;
20092007
}
20102008
}
@@ -2018,8 +2016,7 @@ class FileSystemInfo {
20182016
}
20192017
return capturedItems;
20202018
};
2021-
if (files) {
2022-
const capturedFiles = captureNonManaged(files, managedFiles);
2019+
const processCapturedFiles = capturedFiles => {
20232020
switch (mode) {
20242021
case 3:
20252022
this._fileTshsOptimization.optimize(snapshot, capturedFiles);
@@ -2096,12 +2093,11 @@ class FileSystemInfo {
20962093
}
20972094
break;
20982095
}
2096+
};
2097+
if (files) {
2098+
processCapturedFiles(captureNonManaged(files, managedFiles));
20992099
}
2100-
if (directories) {
2101-
const capturedDirectories = captureNonManaged(
2102-
directories,
2103-
managedContexts
2104-
);
2100+
const processCapturedDirectories = capturedDirectories => {
21052101
switch (mode) {
21062102
case 3:
21072103
this._contextTshsOptimization.optimize(snapshot, capturedDirectories);
@@ -2221,9 +2217,13 @@ class FileSystemInfo {
22212217
}
22222218
break;
22232219
}
2220+
};
2221+
if (directories) {
2222+
processCapturedDirectories(
2223+
captureNonManaged(directories, managedContexts)
2224+
);
22242225
}
2225-
if (missing) {
2226-
const capturedMissing = captureNonManaged(missing, managedMissing);
2226+
const processCapturedMissing = capturedMissing => {
22272227
this._missingExistenceOptimization.optimize(snapshot, capturedMissing);
22282228
for (const path of capturedMissing) {
22292229
const cache = this._fileTimestamps.get(path);
@@ -2248,11 +2248,15 @@ class FileSystemInfo {
22482248
});
22492249
}
22502250
}
2251+
};
2252+
if (missing) {
2253+
processCapturedMissing(captureNonManaged(missing, managedMissing));
22512254
}
22522255
this._managedItemInfoOptimization.optimize(snapshot, managedItems);
22532256
for (const path of managedItems) {
22542257
const cache = this._managedItems.get(path);
22552258
if (cache !== undefined) {
2259+
managedFiles.add(join(this.fs, path, "package.json"));
22562260
managedItemInfo.set(path, cache);
22572261
} else {
22582262
jobs++;
@@ -2264,9 +2268,24 @@ class FileSystemInfo {
22642268
);
22652269
}
22662270
jobError();
2267-
} else {
2271+
} else if (entry) {
2272+
managedFiles.add(join(this.fs, path, "package.json"));
22682273
managedItemInfo.set(path, entry);
22692274
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();
22702289
}
22712290
});
22722291
}
@@ -3479,9 +3498,10 @@ class FileSystemInfo {
34793498
this._managedItems.set(path, "nested");
34803499
return callback(null, "nested");
34813500
}
3482-
const problem = `Managed item ${path} isn't a directory or doesn't contain a package.json`;
3483-
this.logger.warn(problem);
3484-
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();
34853505
});
34863506
return;
34873507
}
@@ -3493,6 +3513,12 @@ class FileSystemInfo {
34933513
} catch (e) {
34943514
return callback(e);
34953515
}
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+
}
34963522
const info = `${data.name || ""}@${data.version || ""}`;
34973523
this._managedItems.set(path, info);
34983524
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