allow RegExp as managed and immutable paths

add all node_modules as managedPaths in futureDefaults
This commit is contained in:
Tobias Koppers 2021-10-18 16:07:41 +02:00
parent ccdeabf735
commit 5e16d642ad
10 changed files with 216 additions and 83 deletions

View File

@ -941,11 +941,11 @@ export interface FileCacheOptions {
/**
* List of paths that are managed by a package manager and contain a version or hash in its path so all files are immutable.
*/
immutablePaths?: string[];
immutablePaths?: (RegExp | string)[];
/**
* List of paths that are managed by a package manager and can be trusted to not be modified otherwise.
*/
managedPaths?: string[];
managedPaths?: (RegExp | string)[];
/**
* Time for which unused cache entries stay in the filesystem cache at minimum (in milliseconds).
*/
@ -2276,11 +2276,11 @@ export interface SnapshotOptions {
/**
* List of paths that are managed by a package manager and contain a version or hash in its path so all files are immutable.
*/
immutablePaths?: string[];
immutablePaths?: (RegExp | string)[];
/**
* List of paths that are managed by a package manager and can be trusted to not be modified otherwise.
*/
managedPaths?: string[];
managedPaths?: (RegExp | string)[];
/**
* Options for snapshotting dependencies of modules to determine if they need to be built again.
*/

View File

@ -219,9 +219,9 @@ class Compiler {
/** @type {string|null} */
this.recordsOutputPath = null;
this.records = {};
/** @type {Set<string>} */
/** @type {Set<string | RegExp>} */
this.managedPaths = new Set();
/** @type {Set<string>} */
/** @type {Set<string | RegExp>} */
this.immutablePaths = new Set();
/** @type {ReadonlySet<string>} */

View File

@ -853,8 +853,8 @@ class FileSystemInfo {
/**
* @param {InputFileSystem} fs file system
* @param {Object} options options
* @param {Iterable<string>=} options.managedPaths paths that are only managed by a package manager
* @param {Iterable<string>=} options.immutablePaths paths that are immutable
* @param {Iterable<string | RegExp>=} options.managedPaths paths that are only managed by a package manager
* @param {Iterable<string | RegExp>=} options.immutablePaths paths that are immutable
* @param {Logger=} options.logger logger used to log invalid snapshots
* @param {string | Hash=} options.hashFunction the hash function to use
*/
@ -996,12 +996,19 @@ class FileSystemInfo {
processor: this._getManagedItemDirectoryInfo.bind(this)
});
this.managedPaths = Array.from(managedPaths);
this.managedPathsWithSlash = this.managedPaths.map(p =>
join(fs, p, "_").slice(0, -1)
this.managedPathsWithSlash = /** @type {string[]} */ (
this.managedPaths.filter(p => typeof p === "string")
).map(p => join(fs, p, "_").slice(0, -1));
this.managedPathsRegExps = /** @type {RegExp[]} */ (
this.managedPaths.filter(p => typeof p !== "string")
);
this.immutablePaths = Array.from(immutablePaths);
this.immutablePathsWithSlash = this.immutablePaths.map(p =>
join(fs, p, "_").slice(0, -1)
this.immutablePathsWithSlash = /** @type {string[]} */ (
this.immutablePaths.filter(p => typeof p === "string")
).map(p => join(fs, p, "_").slice(0, -1));
this.immutablePathsRegExps = /** @type {RegExp[]} */ (
this.immutablePaths.filter(p => typeof p !== "string")
);
this._cachedDeprecatedFileTimestamps = undefined;
@ -1966,12 +1973,29 @@ class FileSystemInfo {
}
};
const checkManaged = (path, managedSet) => {
for (const immutablePath of this.immutablePathsRegExps) {
if (immutablePath.test(path)) {
managedSet.add(path);
return true;
}
}
for (const immutablePath of this.immutablePathsWithSlash) {
if (path.startsWith(immutablePath)) {
managedSet.add(path);
return true;
}
}
for (const managedPath of this.managedPathsRegExps) {
const match = managedPath.exec(path);
if (match) {
const managedItem = getManagedItem(managedPath[1], path);
if (managedItem) {
managedItems.add(managedItem);
managedSet.add(path);
return true;
}
}
}
for (const managedPath of this.managedPathsWithSlash) {
if (path.startsWith(managedPath)) {
const managedItem = getManagedItem(managedPath, path);
@ -2923,10 +2947,29 @@ class FileSystemInfo {
files,
(file, callback) => {
const child = join(this.fs, path, file);
for (const immutablePath of this.immutablePathsRegExps) {
if (immutablePath.test(path)) {
// ignore any immutable path for timestamping
return callback(null, fromImmutablePath(path));
}
}
for (const immutablePath of this.immutablePathsWithSlash) {
if (path.startsWith(immutablePath)) {
// ignore any immutable path for timestamping
return callback(null, fromImmutablePath(immutablePath));
return callback(null, fromImmutablePath(path));
}
}
for (const managedPath of this.managedPathsRegExps) {
const match = managedPath.exec(path);
if (match) {
const managedItem = getManagedItem(managedPath[1], path);
if (managedItem) {
// construct timestampHash from managed info
return this.managedItemQueue.add(managedItem, (err, info) => {
if (err) return callback(err);
return callback(null, fromManagedItem(info));
});
}
}
}
for (const managedPath of this.managedPathsWithSlash) {

View File

@ -9,8 +9,8 @@
class AddManagedPathsPlugin {
/**
* @param {Iterable<string>} managedPaths list of managed paths
* @param {Iterable<string>} immutablePaths list of immutable paths
* @param {Iterable<string | RegExp>} managedPaths list of managed paths
* @param {Iterable<string | RegExp>} immutablePaths list of immutable paths
*/
constructor(managedPaths, immutablePaths) {
this.managedPaths = new Set(managedPaths);

View File

@ -161,6 +161,8 @@ const applyWebpackOptionsDefaults = options => {
applyExperimentsDefaults(options.experiments, { production, development });
const futureDefaults = options.experiments.futureDefaults;
F(options, "cache", () =>
development ? { type: /** @type {"memory"} */ ("memory") } : false
);
@ -172,7 +174,10 @@ const applyWebpackOptionsDefaults = options => {
});
const cache = !!options.cache;
applySnapshotDefaults(options.snapshot, { production });
applySnapshotDefaults(options.snapshot, {
production,
futureDefaults
});
applyModuleDefaults(options.module, {
cache,
@ -192,7 +197,7 @@ const applyWebpackOptionsDefaults = options => {
development,
entry: options.entry,
module: options.module,
futureDefaults: options.experiments.futureDefaults
futureDefaults
});
applyExternalsPresetsDefaults(options.externalsPresets, {
@ -348,49 +353,65 @@ const applyCacheDefaults = (
* @param {SnapshotOptions} snapshot options
* @param {Object} options options
* @param {boolean} options.production is production
* @param {boolean} options.futureDefaults is future defaults enabled
* @returns {void}
*/
const applySnapshotDefaults = (snapshot, { production }) => {
A(snapshot, "managedPaths", () => {
if (process.versions.pnp === "3") {
const match =
/^(.+?)[\\/]cache[\\/]watchpack-npm-[^\\/]+\.zip[\\/]node_modules[\\/]/.exec(
const applySnapshotDefaults = (snapshot, { production, futureDefaults }) => {
if (futureDefaults) {
F(snapshot, "managedPaths", () =>
process.versions.pnp === "3"
? [
/^(.+?(?:[\\/]\.yarn[\\/]unplugged[\\/][^\\/]+)?[\\/]node_modules[\\/])/
]
: [/^(.+?[\\/]node_modules[\\/])/]
);
F(snapshot, "immutablePaths", () =>
process.versions.pnp === "3"
? [/^(.+?[\\/]cache[\\/][^\\/]+\.zip[\\/]node_modules[\\/])/]
: []
);
} else {
A(snapshot, "managedPaths", () => {
if (process.versions.pnp === "3") {
const match =
/^(.+?)[\\/]cache[\\/]watchpack-npm-[^\\/]+\.zip[\\/]node_modules[\\/]/.exec(
require.resolve("watchpack")
);
if (match) {
return [path.resolve(match[1], "unplugged")];
}
} else {
const match = /^(.+?[\\/]node_modules)[\\/]/.exec(
// eslint-disable-next-line node/no-extraneous-require
require.resolve("watchpack")
);
if (match) {
return [path.resolve(match[1], "unplugged")];
if (match) {
return [match[1]];
}
}
} else {
const match = /^(.+?[\\/]node_modules)[\\/]/.exec(
// eslint-disable-next-line node/no-extraneous-require
require.resolve("watchpack")
);
if (match) {
return [match[1]];
return [];
});
A(snapshot, "immutablePaths", () => {
if (process.versions.pnp === "1") {
const match =
/^(.+?[\\/]v4)[\\/]npm-watchpack-[^\\/]+-[\da-f]{40}[\\/]node_modules[\\/]/.exec(
require.resolve("watchpack")
);
if (match) {
return [match[1]];
}
} else if (process.versions.pnp === "3") {
const match =
/^(.+?)[\\/]watchpack-npm-[^\\/]+\.zip[\\/]node_modules[\\/]/.exec(
require.resolve("watchpack")
);
if (match) {
return [match[1]];
}
}
}
return [];
});
A(snapshot, "immutablePaths", () => {
if (process.versions.pnp === "1") {
const match =
/^(.+?[\\/]v4)[\\/]npm-watchpack-[^\\/]+-[\da-f]{40}[\\/]node_modules[\\/]/.exec(
require.resolve("watchpack")
);
if (match) {
return [match[1]];
}
} else if (process.versions.pnp === "3") {
const match =
/^(.+?)[\\/]watchpack-npm-[^\\/]+\.zip[\\/]node_modules[\\/]/.exec(
require.resolve("watchpack")
);
if (match) {
return [match[1]];
}
}
return [];
});
return [];
});
}
F(snapshot, "resolveBuildDependencies", () => ({
timestamp: true,
hash: true

File diff suppressed because one or more lines are too long

View File

@ -1005,20 +1005,40 @@
"description": "List of paths that are managed by a package manager and contain a version or hash in its path so all files are immutable.",
"type": "array",
"items": {
"description": "A path to a immutable directory (usually a package manager cache directory).",
"type": "string",
"absolutePath": true,
"minLength": 1
"description": "List of paths that are managed by a package manager and contain a version or hash in its path so all files are immutable.",
"anyOf": [
{
"description": "A RegExp matching a immutable directory (usually a package manager cache directory, including the tailing slash)",
"instanceof": "RegExp",
"tsType": "RegExp"
},
{
"description": "A path to a immutable directory (usually a package manager cache directory).",
"type": "string",
"absolutePath": true,
"minLength": 1
}
]
}
},
"managedPaths": {
"description": "List of paths that are managed by a package manager and can be trusted to not be modified otherwise.",
"type": "array",
"items": {
"description": "A path to a managed directory (usually a node_modules directory).",
"type": "string",
"absolutePath": true,
"minLength": 1
"description": "List of paths that are managed by a package manager and can be trusted to not be modified otherwise.",
"anyOf": [
{
"description": "A RegExp matching a managed directory (usually a node_modules directory, including the tailing slash)",
"instanceof": "RegExp",
"tsType": "RegExp"
},
{
"description": "A path to a managed directory (usually a node_modules directory).",
"type": "string",
"absolutePath": true,
"minLength": 1
}
]
}
},
"maxAge": {
@ -3952,20 +3972,40 @@
"description": "List of paths that are managed by a package manager and contain a version or hash in its path so all files are immutable.",
"type": "array",
"items": {
"description": "A path to a immutable directory (usually a package manager cache directory).",
"type": "string",
"absolutePath": true,
"minLength": 1
"description": "List of paths that are managed by a package manager and contain a version or hash in its path so all files are immutable.",
"anyOf": [
{
"description": "A RegExp matching a immutable directory (usually a package manager cache directory, including the tailing slash)",
"instanceof": "RegExp",
"tsType": "RegExp"
},
{
"description": "A path to a immutable directory (usually a package manager cache directory).",
"type": "string",
"absolutePath": true,
"minLength": 1
}
]
}
},
"managedPaths": {
"description": "List of paths that are managed by a package manager and can be trusted to not be modified otherwise.",
"type": "array",
"items": {
"description": "A path to a managed directory (usually a node_modules directory).",
"type": "string",
"absolutePath": true,
"minLength": 1
"description": "List of paths that are managed by a package manager and can be trusted to not be modified otherwise.",
"anyOf": [
{
"description": "A RegExp matching a managed directory (usually a node_modules directory, including the tailing slash)",
"instanceof": "RegExp",
"tsType": "RegExp"
},
{
"description": "A path to a managed directory (usually a node_modules directory).",
"type": "string",
"absolutePath": true,
"minLength": 1
}
]
}
},
"module": {

View File

@ -1910,6 +1910,9 @@ Object {
@@ ... @@
- "hashFunction": "md4",
+ "hashFunction": "xxhash64",
@@ ... @@
- "<cwd>/node_modules",
+ /^(.+?[\\\\/]node_modules[\\\\/])/,
`)
);
});

View File

@ -180,6 +180,12 @@ Object {
},
"cache-immutable-paths": Object {
"configs": Array [
Object {
"description": "A RegExp matching a immutable directory (usually a package manager cache directory, including the tailing slash)",
"multiple": true,
"path": "cache.immutablePaths[]",
"type": "RegExp",
},
Object {
"description": "A path to a immutable directory (usually a package manager cache directory).",
"multiple": true,
@ -187,7 +193,7 @@ Object {
"type": "path",
},
],
"description": "A path to a immutable directory (usually a package manager cache directory).",
"description": "A RegExp matching a immutable directory (usually a package manager cache directory, including the tailing slash) A path to a immutable directory (usually a package manager cache directory).",
"multiple": true,
"simpleType": "string",
},
@ -206,6 +212,12 @@ Object {
},
"cache-managed-paths": Object {
"configs": Array [
Object {
"description": "A RegExp matching a managed directory (usually a node_modules directory, including the tailing slash)",
"multiple": true,
"path": "cache.managedPaths[]",
"type": "RegExp",
},
Object {
"description": "A path to a managed directory (usually a node_modules directory).",
"multiple": true,
@ -213,7 +225,7 @@ Object {
"type": "path",
},
],
"description": "A path to a managed directory (usually a node_modules directory).",
"description": "A RegExp matching a managed directory (usually a node_modules directory, including the tailing slash) A path to a managed directory (usually a node_modules directory).",
"multiple": true,
"simpleType": "string",
},
@ -7058,6 +7070,12 @@ Object {
},
"snapshot-immutable-paths": Object {
"configs": Array [
Object {
"description": "A RegExp matching a immutable directory (usually a package manager cache directory, including the tailing slash)",
"multiple": true,
"path": "snapshot.immutablePaths[]",
"type": "RegExp",
},
Object {
"description": "A path to a immutable directory (usually a package manager cache directory).",
"multiple": true,
@ -7065,7 +7083,7 @@ Object {
"type": "path",
},
],
"description": "A path to a immutable directory (usually a package manager cache directory).",
"description": "A RegExp matching a immutable directory (usually a package manager cache directory, including the tailing slash) A path to a immutable directory (usually a package manager cache directory).",
"multiple": true,
"simpleType": "string",
},
@ -7084,6 +7102,12 @@ Object {
},
"snapshot-managed-paths": Object {
"configs": Array [
Object {
"description": "A RegExp matching a managed directory (usually a node_modules directory, including the tailing slash)",
"multiple": true,
"path": "snapshot.managedPaths[]",
"type": "RegExp",
},
Object {
"description": "A path to a managed directory (usually a node_modules directory).",
"multiple": true,
@ -7091,7 +7115,7 @@ Object {
"type": "path",
},
],
"description": "A path to a managed directory (usually a node_modules directory).",
"description": "A RegExp matching a managed directory (usually a node_modules directory, including the tailing slash) A path to a managed directory (usually a node_modules directory).",
"multiple": true,
"simpleType": "string",
},

18
types.d.ts vendored
View File

@ -1895,8 +1895,8 @@ declare class Compiler {
recordsInputPath: null | string;
recordsOutputPath: null | string;
records: object;
managedPaths: Set<string>;
immutablePaths: Set<string>;
managedPaths: Set<string | RegExp>;
immutablePaths: Set<string | RegExp>;
modifiedFiles: ReadonlySet<string>;
removedFiles: ReadonlySet<string>;
fileTimestamps: ReadonlyMap<string, null | FileSystemInfoEntry | "ignore">;
@ -3933,12 +3933,12 @@ declare interface FileCacheOptions {
/**
* List of paths that are managed by a package manager and contain a version or hash in its path so all files are immutable.
*/
immutablePaths?: string[];
immutablePaths?: (string | RegExp)[];
/**
* List of paths that are managed by a package manager and can be trusted to not be modified otherwise.
*/
managedPaths?: string[];
managedPaths?: (string | RegExp)[];
/**
* Time for which unused cache entries stay in the filesystem cache at minimum (in milliseconds).
@ -4051,10 +4051,12 @@ declare abstract class FileSystemInfo {
contextTshQueue: AsyncQueue<string, string, null | ContextTimestampAndHash>;
managedItemQueue: AsyncQueue<string, string, null | string>;
managedItemDirectoryQueue: AsyncQueue<string, string, Set<string>>;
managedPaths: string[];
managedPaths: (string | RegExp)[];
managedPathsWithSlash: string[];
immutablePaths: string[];
managedPathsRegExps: RegExp[];
immutablePaths: (string | RegExp)[];
immutablePathsWithSlash: string[];
immutablePathsRegExps: RegExp[];
logStatistics(): void;
clear(): void;
addFileTimestamps(
@ -10516,12 +10518,12 @@ declare interface SnapshotOptions {
/**
* List of paths that are managed by a package manager and contain a version or hash in its path so all files are immutable.
*/
immutablePaths?: string[];
immutablePaths?: (string | RegExp)[];
/**
* List of paths that are managed by a package manager and can be trusted to not be modified otherwise.
*/
managedPaths?: string[];
managedPaths?: (string | RegExp)[];
/**
* Options for snapshotting dependencies of modules to determine if they need to be built again.