webpack 5.27.2 → 5.31.0
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.
Potentially problematic release.
This version of webpack might be problematic. Click here for more details.
- package/lib/Compiler.js +4 -0
- package/lib/Dependency.js +4 -0
- package/lib/ExportsInfo.js +62 -28
- package/lib/FileSystemInfo.js +206 -43
- package/lib/FlagDependencyExportsPlugin.js +12 -3
- package/lib/NormalModule.js +4 -0
- package/lib/WebpackOptionsApply.js +24 -7
- package/lib/asset/AssetGenerator.js +84 -12
- package/lib/asset/AssetModulesPlugin.js +3 -0
- package/lib/cache/IdleFileCachePlugin.js +26 -16
- package/lib/cache/MemoryCachePlugin.js +6 -0
- package/lib/cache/MemoryWithGcCachePlugin.js +129 -0
- package/lib/cache/PackFileCacheStrategy.js +97 -15
- package/lib/config/defaults.js +16 -4
- package/lib/config/normalization.js +6 -2
- package/lib/dependencies/HarmonyExportExpressionDependency.js +1 -0
- package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +5 -0
- package/lib/dependencies/HarmonyExportSpecifierDependency.js +1 -0
- package/lib/hmr/HotModuleReplacement.runtime.js +3 -2
- package/lib/hmr/JavascriptHotModuleReplacement.runtime.js +1 -1
- package/lib/index.js +28 -0
- package/lib/javascript/JavascriptParser.js +4 -0
- package/lib/logging/createConsoleLogger.js +19 -1
- package/lib/node/NodeEnvironmentPlugin.js +18 -11
- package/lib/node/nodeConsole.js +121 -112
- package/lib/serialization/ObjectMiddleware.js +50 -30
- package/lib/stats/DefaultStatsFactoryPlugin.js +2 -2
- package/lib/util/deterministicGrouping.js +38 -4
- package/lib/util/runtime.js +1 -1
- package/package.json +2 -2
- package/schemas/WebpackOptions.json +50 -1
- package/types.d.ts +155 -18
@@ -15,6 +15,7 @@ const { makePathsRelative } = require("../util/identifier");
|
|
15
15
|
|
16
16
|
/** @typedef {import("webpack-sources").Source} Source */
|
17
17
|
/** @typedef {import("../../declarations/WebpackOptions").AssetGeneratorOptions} AssetGeneratorOptions */
|
18
|
+
/** @typedef {import("../../declarations/WebpackOptions").RawPublicPath} RawPublicPath */
|
18
19
|
/** @typedef {import("../Compilation")} Compilation */
|
19
20
|
/** @typedef {import("../Compiler")} Compiler */
|
20
21
|
/** @typedef {import("../Generator").GenerateContext} GenerateContext */
|
@@ -24,6 +25,55 @@ const { makePathsRelative } = require("../util/identifier");
|
|
24
25
|
/** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */
|
25
26
|
/** @typedef {import("../util/Hash")} Hash */
|
26
27
|
|
28
|
+
const mergeMaybeArrays = (a, b) => {
|
29
|
+
const set = new Set();
|
30
|
+
if (Array.isArray(a)) for (const item of a) set.add(item);
|
31
|
+
else set.add(a);
|
32
|
+
if (Array.isArray(b)) for (const item of b) set.add(item);
|
33
|
+
else set.add(b);
|
34
|
+
return Array.from(set);
|
35
|
+
};
|
36
|
+
|
37
|
+
const mergeAssetInfo = (a, b) => {
|
38
|
+
const result = { ...a, ...b };
|
39
|
+
for (const key of Object.keys(a)) {
|
40
|
+
if (key in b) {
|
41
|
+
if (a[key] === b[key]) continue;
|
42
|
+
switch (key) {
|
43
|
+
case "fullhash":
|
44
|
+
case "chunkhash":
|
45
|
+
case "modulehash":
|
46
|
+
case "contenthash":
|
47
|
+
result[key] = mergeMaybeArrays(a[key], b[key]);
|
48
|
+
break;
|
49
|
+
case "immutable":
|
50
|
+
case "development":
|
51
|
+
case "hotModuleReplacement":
|
52
|
+
case "javascriptModule ":
|
53
|
+
result[key] = a[key] || b[key];
|
54
|
+
break;
|
55
|
+
case "related":
|
56
|
+
result[key] = mergeRelatedInfo(a[key], b[key]);
|
57
|
+
break;
|
58
|
+
default:
|
59
|
+
throw new Error(`Can't handle conflicting asset info for ${key}`);
|
60
|
+
}
|
61
|
+
}
|
62
|
+
}
|
63
|
+
return result;
|
64
|
+
};
|
65
|
+
|
66
|
+
const mergeRelatedInfo = (a, b) => {
|
67
|
+
const result = { ...a, ...b };
|
68
|
+
for (const key of Object.keys(a)) {
|
69
|
+
if (key in b) {
|
70
|
+
if (a[key] === b[key]) continue;
|
71
|
+
result[key] = mergeMaybeArrays(a[key], b[key]);
|
72
|
+
}
|
73
|
+
}
|
74
|
+
return result;
|
75
|
+
};
|
76
|
+
|
27
77
|
const JS_TYPES = new Set(["javascript"]);
|
28
78
|
const JS_AND_ASSET_TYPES = new Set(["javascript", "asset"]);
|
29
79
|
|
@@ -31,12 +81,14 @@ class AssetGenerator extends Generator {
|
|
31
81
|
/**
|
32
82
|
* @param {AssetGeneratorOptions["dataUrl"]=} dataUrlOptions the options for the data url
|
33
83
|
* @param {string=} filename override for output.assetModuleFilename
|
84
|
+
* @param {RawPublicPath=} publicPath override for output.assetModulePublicPath
|
34
85
|
* @param {boolean=} emit generate output asset
|
35
86
|
*/
|
36
|
-
constructor(dataUrlOptions, filename, emit) {
|
87
|
+
constructor(dataUrlOptions, filename, publicPath, emit) {
|
37
88
|
super();
|
38
89
|
this.dataUrlOptions = dataUrlOptions;
|
39
90
|
this.filename = filename;
|
91
|
+
this.publicPath = publicPath;
|
40
92
|
this.emit = emit;
|
41
93
|
}
|
42
94
|
|
@@ -131,9 +183,9 @@ class AssetGenerator extends Generator {
|
|
131
183
|
module.matchResource || module.resource,
|
132
184
|
runtimeTemplate.compilation.compiler.root
|
133
185
|
).replace(/^\.\//, "");
|
134
|
-
|
186
|
+
let {
|
135
187
|
path: filename,
|
136
|
-
info
|
188
|
+
info: assetInfo
|
137
189
|
} = runtimeTemplate.compilation.getAssetPathWithInfo(
|
138
190
|
assetModuleFilename,
|
139
191
|
{
|
@@ -144,11 +196,33 @@ class AssetGenerator extends Generator {
|
|
144
196
|
contentHash
|
145
197
|
}
|
146
198
|
);
|
147
|
-
|
148
|
-
|
199
|
+
let publicPath;
|
200
|
+
if (this.publicPath) {
|
201
|
+
const {
|
202
|
+
path,
|
203
|
+
info
|
204
|
+
} = runtimeTemplate.compilation.getAssetPathWithInfo(
|
205
|
+
this.publicPath,
|
206
|
+
{
|
207
|
+
module,
|
208
|
+
runtime,
|
209
|
+
filename: sourceFilename,
|
210
|
+
chunkGraph,
|
211
|
+
contentHash
|
212
|
+
}
|
213
|
+
);
|
214
|
+
publicPath = JSON.stringify(path);
|
215
|
+
assetInfo = mergeAssetInfo(assetInfo, info);
|
216
|
+
} else {
|
217
|
+
publicPath = RuntimeGlobals.publicPath;
|
218
|
+
runtimeRequirements.add(RuntimeGlobals.publicPath); // add __webpack_require__.p
|
219
|
+
}
|
220
|
+
assetInfo = {
|
149
221
|
sourceFilename,
|
150
|
-
...
|
222
|
+
...assetInfo
|
151
223
|
};
|
224
|
+
module.buildInfo.filename = filename;
|
225
|
+
module.buildInfo.assetInfo = assetInfo;
|
152
226
|
if (getData) {
|
153
227
|
// Due to code generation caching module.buildInfo.XXX can't used to store such information
|
154
228
|
// It need to be stored in the code generation results instead, where it's cached too
|
@@ -156,15 +230,13 @@ class AssetGenerator extends Generator {
|
|
156
230
|
const data = getData();
|
157
231
|
data.set("fullContentHash", fullHash);
|
158
232
|
data.set("filename", filename);
|
159
|
-
data.set("assetInfo",
|
233
|
+
data.set("assetInfo", assetInfo);
|
160
234
|
}
|
161
235
|
|
162
|
-
runtimeRequirements.add(RuntimeGlobals.publicPath); // add __webpack_require__.p
|
163
|
-
|
164
236
|
return new RawSource(
|
165
|
-
`${
|
166
|
-
RuntimeGlobals.
|
167
|
-
} + ${JSON.stringify(filename)};`
|
237
|
+
`${
|
238
|
+
RuntimeGlobals.module
|
239
|
+
}.exports = ${publicPath} + ${JSON.stringify(filename)};`
|
168
240
|
);
|
169
241
|
}
|
170
242
|
}
|
@@ -118,8 +118,10 @@ class AssetModulesPlugin {
|
|
118
118
|
}
|
119
119
|
|
120
120
|
let filename = undefined;
|
121
|
+
let publicPath = undefined;
|
121
122
|
if (type !== "asset/inline") {
|
122
123
|
filename = generatorOptions.filename;
|
124
|
+
publicPath = generatorOptions.publicPath;
|
123
125
|
}
|
124
126
|
|
125
127
|
const AssetGenerator = getAssetGenerator();
|
@@ -127,6 +129,7 @@ class AssetModulesPlugin {
|
|
127
129
|
return new AssetGenerator(
|
128
130
|
dataUrl,
|
129
131
|
filename,
|
132
|
+
publicPath,
|
130
133
|
generatorOptions.emit !== false
|
131
134
|
);
|
132
135
|
});
|
@@ -30,7 +30,7 @@ class IdleFileCachePlugin {
|
|
30
30
|
* @returns {void}
|
31
31
|
*/
|
32
32
|
apply(compiler) {
|
33
|
-
|
33
|
+
let strategy = this.strategy;
|
34
34
|
const idleTimeout = this.idleTimeout;
|
35
35
|
const idleTimeoutForInitialStore = Math.min(
|
36
36
|
idleTimeout,
|
@@ -54,20 +54,27 @@ class IdleFileCachePlugin {
|
|
54
54
|
compiler.cache.hooks.get.tapPromise(
|
55
55
|
{ name: "IdleFileCachePlugin", stage: Cache.STAGE_DISK },
|
56
56
|
(identifier, etag, gotHandlers) => {
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
57
|
+
const restore = () =>
|
58
|
+
strategy.restore(identifier, etag).then(cacheEntry => {
|
59
|
+
if (cacheEntry === undefined) {
|
60
|
+
gotHandlers.push((result, callback) => {
|
61
|
+
if (result !== undefined) {
|
62
|
+
pendingIdleTasks.set(identifier, () =>
|
63
|
+
strategy.store(identifier, etag, result)
|
64
|
+
);
|
65
|
+
}
|
66
|
+
callback();
|
67
|
+
});
|
68
|
+
} else {
|
69
|
+
return cacheEntry;
|
70
|
+
}
|
71
|
+
});
|
72
|
+
const pendingTask = pendingIdleTasks.get(identifier);
|
73
|
+
if (pendingTask !== undefined) {
|
74
|
+
pendingIdleTasks.delete(identifier);
|
75
|
+
return pendingTask().then(restore);
|
76
|
+
}
|
77
|
+
return restore();
|
71
78
|
}
|
72
79
|
);
|
73
80
|
|
@@ -101,7 +108,10 @@ class IdleFileCachePlugin {
|
|
101
108
|
reportProgress(1, `stored`);
|
102
109
|
});
|
103
110
|
}
|
104
|
-
return currentIdlePromise
|
111
|
+
return currentIdlePromise.then(() => {
|
112
|
+
// Reset strategy
|
113
|
+
if (strategy.clear) strategy.clear();
|
114
|
+
});
|
105
115
|
}
|
106
116
|
);
|
107
117
|
|
@@ -0,0 +1,129 @@
|
|
1
|
+
/*
|
2
|
+
MIT License http://www.opensource.org/licenses/mit-license.php
|
3
|
+
Author Tobias Koppers @sokra
|
4
|
+
*/
|
5
|
+
|
6
|
+
"use strict";
|
7
|
+
|
8
|
+
const Cache = require("../Cache");
|
9
|
+
|
10
|
+
/** @typedef {import("webpack-sources").Source} Source */
|
11
|
+
/** @typedef {import("../Cache").Etag} Etag */
|
12
|
+
/** @typedef {import("../Compiler")} Compiler */
|
13
|
+
/** @typedef {import("../Module")} Module */
|
14
|
+
|
15
|
+
class MemoryWithGcCachePlugin {
|
16
|
+
constructor({ maxGenerations }) {
|
17
|
+
this._maxGenerations = maxGenerations;
|
18
|
+
}
|
19
|
+
/**
|
20
|
+
* Apply the plugin
|
21
|
+
* @param {Compiler} compiler the compiler instance
|
22
|
+
* @returns {void}
|
23
|
+
*/
|
24
|
+
apply(compiler) {
|
25
|
+
const maxGenerations = this._maxGenerations;
|
26
|
+
/** @type {Map<string, { etag: Etag | null, data: any }>} */
|
27
|
+
const cache = new Map();
|
28
|
+
/** @type {Map<string, { entry: { etag: Etag | null, data: any }, until: number }>} */
|
29
|
+
const oldCache = new Map();
|
30
|
+
let generation = 0;
|
31
|
+
let cachePosition = 0;
|
32
|
+
const logger = compiler.getInfrastructureLogger("MemoryWithGcCachePlugin");
|
33
|
+
compiler.hooks.afterDone.tap("MemoryWithGcCachePlugin", () => {
|
34
|
+
generation++;
|
35
|
+
let clearedEntries = 0;
|
36
|
+
let lastClearedIdentifier;
|
37
|
+
for (const [identifier, entry] of oldCache) {
|
38
|
+
if (entry.until > generation) break;
|
39
|
+
|
40
|
+
oldCache.delete(identifier);
|
41
|
+
if (cache.get(identifier) === undefined) {
|
42
|
+
cache.delete(identifier);
|
43
|
+
clearedEntries++;
|
44
|
+
lastClearedIdentifier = identifier;
|
45
|
+
}
|
46
|
+
}
|
47
|
+
if (clearedEntries > 0 || oldCache.size > 0) {
|
48
|
+
logger.log(
|
49
|
+
`${cache.size - oldCache.size} active entries, ${
|
50
|
+
oldCache.size
|
51
|
+
} recently unused cached entries${
|
52
|
+
clearedEntries > 0
|
53
|
+
? `, ${clearedEntries} old unused cache entries removed e. g. ${lastClearedIdentifier}`
|
54
|
+
: ""
|
55
|
+
}`
|
56
|
+
);
|
57
|
+
}
|
58
|
+
let i = (cache.size / maxGenerations) | 0;
|
59
|
+
let j = cachePosition >= cache.size ? 0 : cachePosition;
|
60
|
+
cachePosition = j + i;
|
61
|
+
for (const [identifier, entry] of cache) {
|
62
|
+
if (j !== 0) {
|
63
|
+
j--;
|
64
|
+
continue;
|
65
|
+
}
|
66
|
+
if (entry !== undefined) {
|
67
|
+
// We don't delete the cache entry, but set it to undefined instead
|
68
|
+
// This reserves the location in the data table and avoids rehashing
|
69
|
+
// when constantly adding and removing entries.
|
70
|
+
// It will be deleted when removed from oldCache.
|
71
|
+
cache.set(identifier, undefined);
|
72
|
+
oldCache.delete(identifier);
|
73
|
+
oldCache.set(identifier, {
|
74
|
+
entry,
|
75
|
+
until: generation + maxGenerations
|
76
|
+
});
|
77
|
+
if (i-- === 0) break;
|
78
|
+
}
|
79
|
+
}
|
80
|
+
});
|
81
|
+
compiler.cache.hooks.store.tap(
|
82
|
+
{ name: "MemoryWithGcCachePlugin", stage: Cache.STAGE_MEMORY },
|
83
|
+
(identifier, etag, data) => {
|
84
|
+
cache.set(identifier, { etag, data });
|
85
|
+
}
|
86
|
+
);
|
87
|
+
compiler.cache.hooks.get.tap(
|
88
|
+
{ name: "MemoryWithGcCachePlugin", stage: Cache.STAGE_MEMORY },
|
89
|
+
(identifier, etag, gotHandlers) => {
|
90
|
+
const cacheEntry = cache.get(identifier);
|
91
|
+
if (cacheEntry === null) {
|
92
|
+
return null;
|
93
|
+
} else if (cacheEntry !== undefined) {
|
94
|
+
return cacheEntry.etag === etag ? cacheEntry.data : null;
|
95
|
+
}
|
96
|
+
const oldCacheEntry = oldCache.get(identifier);
|
97
|
+
if (oldCacheEntry !== undefined) {
|
98
|
+
const cacheEntry = oldCacheEntry.entry;
|
99
|
+
if (cacheEntry === null) {
|
100
|
+
oldCache.delete(identifier);
|
101
|
+
cache.set(identifier, cacheEntry);
|
102
|
+
return null;
|
103
|
+
} else {
|
104
|
+
if (cacheEntry.etag !== etag) return null;
|
105
|
+
oldCache.delete(identifier);
|
106
|
+
cache.set(identifier, cacheEntry);
|
107
|
+
return cacheEntry.data;
|
108
|
+
}
|
109
|
+
}
|
110
|
+
gotHandlers.push((result, callback) => {
|
111
|
+
if (result === undefined) {
|
112
|
+
cache.set(identifier, null);
|
113
|
+
} else {
|
114
|
+
cache.set(identifier, { etag, data: result });
|
115
|
+
}
|
116
|
+
return callback();
|
117
|
+
});
|
118
|
+
}
|
119
|
+
);
|
120
|
+
compiler.cache.hooks.shutdown.tap(
|
121
|
+
{ name: "MemoryWithGcCachePlugin", stage: Cache.STAGE_MEMORY },
|
122
|
+
() => {
|
123
|
+
cache.clear();
|
124
|
+
oldCache.clear();
|
125
|
+
}
|
126
|
+
);
|
127
|
+
}
|
128
|
+
}
|
129
|
+
module.exports = MemoryWithGcCachePlugin;
|
@@ -29,7 +29,7 @@ class PackContainer {
|
|
29
29
|
* @param {string} version version identifier
|
30
30
|
* @param {Snapshot} buildSnapshot snapshot of all build dependencies
|
31
31
|
* @param {Set<string>} buildDependencies list of all unresolved build dependencies captured
|
32
|
-
* @param {Map<string, string>} resolveResults result of the resolved build dependencies
|
32
|
+
* @param {Map<string, string | false>} resolveResults result of the resolved build dependencies
|
33
33
|
* @param {Snapshot} resolveBuildDependenciesSnapshot snapshot of the dependencies of the build dependencies resolving
|
34
34
|
*/
|
35
35
|
constructor(
|
@@ -75,7 +75,6 @@ makeSerializable(
|
|
75
75
|
|
76
76
|
const MIN_CONTENT_SIZE = 1024 * 1024; // 1 MB
|
77
77
|
const CONTENT_COUNT_TO_MERGE = 10;
|
78
|
-
const MAX_AGE = 1000 * 60 * 60 * 24 * 60; // 1 month
|
79
78
|
const MAX_ITEMS_IN_FRESH_PACK = 50000;
|
80
79
|
|
81
80
|
class PackItemInfo {
|
@@ -94,7 +93,7 @@ class PackItemInfo {
|
|
94
93
|
}
|
95
94
|
|
96
95
|
class Pack {
|
97
|
-
constructor(logger) {
|
96
|
+
constructor(logger, maxAge) {
|
98
97
|
/** @type {Map<string, PackItemInfo>} */
|
99
98
|
this.itemInfo = new Map();
|
100
99
|
/** @type {string[]} */
|
@@ -105,6 +104,7 @@ class Pack {
|
|
105
104
|
this.content = [];
|
106
105
|
this.invalid = false;
|
107
106
|
this.logger = logger;
|
107
|
+
this.maxAge = maxAge;
|
108
108
|
}
|
109
109
|
|
110
110
|
/**
|
@@ -167,6 +167,21 @@ class Pack {
|
|
167
167
|
}
|
168
168
|
}
|
169
169
|
|
170
|
+
getContentStats() {
|
171
|
+
let count = 0;
|
172
|
+
let size = 0;
|
173
|
+
for (const content of this.content) {
|
174
|
+
if (content !== undefined) {
|
175
|
+
count++;
|
176
|
+
const s = content.getSize();
|
177
|
+
if (s > 0) {
|
178
|
+
size += s;
|
179
|
+
}
|
180
|
+
}
|
181
|
+
}
|
182
|
+
return { count, size };
|
183
|
+
}
|
184
|
+
|
170
185
|
/**
|
171
186
|
* @returns {number} new location of data entries
|
172
187
|
*/
|
@@ -182,7 +197,7 @@ class Pack {
|
|
182
197
|
const now = Date.now();
|
183
198
|
for (const identifier of items) {
|
184
199
|
const info = this.itemInfo.get(identifier);
|
185
|
-
if (now - info.lastAccess >
|
200
|
+
if (now - info.lastAccess > this.maxAge) {
|
186
201
|
this.itemInfo.delete(identifier);
|
187
202
|
items.delete(identifier);
|
188
203
|
usedItems.delete(identifier);
|
@@ -194,9 +209,10 @@ class Pack {
|
|
194
209
|
}
|
195
210
|
if (count > 0) {
|
196
211
|
this.logger.log(
|
197
|
-
"Garbage Collected %d old items at pack %d e. g. %s",
|
212
|
+
"Garbage Collected %d old items at pack %d (%d items remaining) e. g. %s",
|
198
213
|
count,
|
199
214
|
newLoc,
|
215
|
+
items.size,
|
200
216
|
lastGC
|
201
217
|
);
|
202
218
|
}
|
@@ -426,10 +442,45 @@ class Pack {
|
|
426
442
|
}
|
427
443
|
}
|
428
444
|
|
445
|
+
/**
|
446
|
+
* Find the content with the oldest item and run GC on that.
|
447
|
+
* Only runs for one content to avoid large invalidation.
|
448
|
+
*/
|
449
|
+
_gcOldestContent() {
|
450
|
+
/** @type {PackItemInfo} */
|
451
|
+
let oldest = undefined;
|
452
|
+
for (const info of this.itemInfo.values()) {
|
453
|
+
if (oldest === undefined || info.lastAccess < oldest.lastAccess) {
|
454
|
+
oldest = info;
|
455
|
+
}
|
456
|
+
}
|
457
|
+
if (Date.now() - oldest.lastAccess > this.maxAge) {
|
458
|
+
const loc = oldest.location;
|
459
|
+
if (loc < 0) return;
|
460
|
+
const content = this.content[loc];
|
461
|
+
const items = new Set(content.items);
|
462
|
+
const usedItems = new Set(content.used);
|
463
|
+
this._gcAndUpdateLocation(items, usedItems, loc);
|
464
|
+
|
465
|
+
this.content[loc] =
|
466
|
+
items.size > 0
|
467
|
+
? new PackContent(items, usedItems, async () => {
|
468
|
+
await content.unpack();
|
469
|
+
const map = new Map();
|
470
|
+
for (const identifier of items) {
|
471
|
+
map.set(identifier, content.content.get(identifier));
|
472
|
+
}
|
473
|
+
return new PackContentItems(map);
|
474
|
+
})
|
475
|
+
: undefined;
|
476
|
+
}
|
477
|
+
}
|
478
|
+
|
429
479
|
serialize({ write, writeSeparate }) {
|
430
480
|
this._persistFreshContent();
|
431
481
|
this._optimizeSmallContent();
|
432
482
|
this._optimizeUnusedContent();
|
483
|
+
this._gcOldestContent();
|
433
484
|
for (const identifier of this.itemInfo.keys()) {
|
434
485
|
write(identifier);
|
435
486
|
}
|
@@ -727,6 +778,7 @@ class PackFileCacheStrategy {
|
|
727
778
|
* @param {string} options.version version identifier
|
728
779
|
* @param {Logger} options.logger a logger
|
729
780
|
* @param {SnapshotOptions} options.snapshot options regarding snapshotting
|
781
|
+
* @param {number} options.maxAge max age of cache items
|
730
782
|
*/
|
731
783
|
constructor({
|
732
784
|
compiler,
|
@@ -735,7 +787,8 @@ class PackFileCacheStrategy {
|
|
735
787
|
cacheLocation,
|
736
788
|
version,
|
737
789
|
logger,
|
738
|
-
snapshot
|
790
|
+
snapshot,
|
791
|
+
maxAge
|
739
792
|
}) {
|
740
793
|
this.fileSerializer = createFileSerializer(fs);
|
741
794
|
this.fileSystemInfo = new FileSystemInfo(fs, {
|
@@ -748,6 +801,7 @@ class PackFileCacheStrategy {
|
|
748
801
|
this.cacheLocation = cacheLocation;
|
749
802
|
this.version = version;
|
750
803
|
this.logger = logger;
|
804
|
+
this.maxAge = maxAge;
|
751
805
|
this.snapshot = snapshot;
|
752
806
|
/** @type {Set<string>} */
|
753
807
|
this.buildDependencies = new Set();
|
@@ -755,12 +809,20 @@ class PackFileCacheStrategy {
|
|
755
809
|
this.newBuildDependencies = new LazySet();
|
756
810
|
/** @type {Snapshot} */
|
757
811
|
this.resolveBuildDependenciesSnapshot = undefined;
|
758
|
-
/** @type {Map<string, string>} */
|
812
|
+
/** @type {Map<string, string | false>} */
|
759
813
|
this.resolveResults = undefined;
|
760
814
|
/** @type {Snapshot} */
|
761
815
|
this.buildSnapshot = undefined;
|
762
816
|
/** @type {Promise<Pack>} */
|
763
817
|
this.packPromise = this._openPack();
|
818
|
+
this.storePromise = Promise.resolve();
|
819
|
+
}
|
820
|
+
|
821
|
+
_getPack() {
|
822
|
+
if (this.packPromise === undefined) {
|
823
|
+
this.packPromise = this.storePromise.then(() => this._openPack());
|
824
|
+
}
|
825
|
+
return this.packPromise;
|
764
826
|
}
|
765
827
|
|
766
828
|
/**
|
@@ -776,7 +838,7 @@ class PackFileCacheStrategy {
|
|
776
838
|
let newBuildDependencies;
|
777
839
|
/** @type {Snapshot} */
|
778
840
|
let resolveBuildDependenciesSnapshot;
|
779
|
-
/** @type {Map<string, string>} */
|
841
|
+
/** @type {Map<string, string | false>} */
|
780
842
|
let resolveResults;
|
781
843
|
logger.time("restore cache container");
|
782
844
|
return this.fileSerializer
|
@@ -899,6 +961,7 @@ class PackFileCacheStrategy {
|
|
899
961
|
})
|
900
962
|
.then(pack => {
|
901
963
|
if (pack) {
|
964
|
+
pack.maxAge = this.maxAge;
|
902
965
|
this.buildSnapshot = buildSnapshot;
|
903
966
|
if (buildDependencies) this.buildDependencies = buildDependencies;
|
904
967
|
if (newBuildDependencies)
|
@@ -907,14 +970,14 @@ class PackFileCacheStrategy {
|
|
907
970
|
this.resolveBuildDependenciesSnapshot = resolveBuildDependenciesSnapshot;
|
908
971
|
return pack;
|
909
972
|
}
|
910
|
-
return new Pack(logger);
|
973
|
+
return new Pack(logger, this.maxAge);
|
911
974
|
})
|
912
975
|
.catch(err => {
|
913
976
|
this.logger.warn(
|
914
977
|
`Restoring pack from ${cacheLocation}.pack failed: ${err}`
|
915
978
|
);
|
916
979
|
this.logger.debug(err.stack);
|
917
|
-
return new Pack(logger);
|
980
|
+
return new Pack(logger, this.maxAge);
|
918
981
|
});
|
919
982
|
}
|
920
983
|
|
@@ -925,7 +988,7 @@ class PackFileCacheStrategy {
|
|
925
988
|
* @returns {Promise<void>} promise
|
926
989
|
*/
|
927
990
|
store(identifier, etag, data) {
|
928
|
-
return this.
|
991
|
+
return this._getPack().then(pack => {
|
929
992
|
pack.set(identifier, etag === null ? null : etag.toString(), data);
|
930
993
|
});
|
931
994
|
}
|
@@ -936,7 +999,7 @@ class PackFileCacheStrategy {
|
|
936
999
|
* @returns {Promise<any>} promise to the cached content
|
937
1000
|
*/
|
938
1001
|
restore(identifier, etag) {
|
939
|
-
return this.
|
1002
|
+
return this._getPack()
|
940
1003
|
.then(pack =>
|
941
1004
|
pack.get(identifier, etag === null ? null : etag.toString())
|
942
1005
|
)
|
@@ -955,8 +1018,11 @@ class PackFileCacheStrategy {
|
|
955
1018
|
}
|
956
1019
|
|
957
1020
|
afterAllStored() {
|
1021
|
+
const packPromise = this.packPromise;
|
1022
|
+
if (packPromise === undefined) return Promise.resolve();
|
958
1023
|
const reportProgress = ProgressPlugin.getReporter(this.compiler);
|
959
|
-
|
1024
|
+
this.packPromise = undefined;
|
1025
|
+
return (this.storePromise = packPromise
|
960
1026
|
.then(pack => {
|
961
1027
|
if (!pack.invalid) return;
|
962
1028
|
this.logger.log(`Storing pack...`);
|
@@ -1100,7 +1166,13 @@ class PackFileCacheStrategy {
|
|
1100
1166
|
}
|
1101
1167
|
this.newBuildDependencies.clear();
|
1102
1168
|
this.logger.timeEnd(`store pack`);
|
1103
|
-
|
1169
|
+
const stats = pack.getContentStats();
|
1170
|
+
this.logger.log(
|
1171
|
+
"Stored pack (%d items, %d files, %d MiB)",
|
1172
|
+
pack.itemInfo.size,
|
1173
|
+
stats.count,
|
1174
|
+
Math.round(stats.size / 1024 / 1024)
|
1175
|
+
);
|
1104
1176
|
})
|
1105
1177
|
.catch(err => {
|
1106
1178
|
this.logger.timeEnd(`store pack`);
|
@@ -1112,7 +1184,17 @@ class PackFileCacheStrategy {
|
|
1112
1184
|
.catch(err => {
|
1113
1185
|
this.logger.warn(`Caching failed for pack: ${err}`);
|
1114
1186
|
this.logger.debug(err.stack);
|
1115
|
-
});
|
1187
|
+
}));
|
1188
|
+
}
|
1189
|
+
|
1190
|
+
clear() {
|
1191
|
+
this.fileSystemInfo.clear();
|
1192
|
+
this.buildDependencies.clear();
|
1193
|
+
this.newBuildDependencies.clear();
|
1194
|
+
this.resolveBuildDependenciesSnapshot = undefined;
|
1195
|
+
this.resolveResults = undefined;
|
1196
|
+
this.buildSnapshot = undefined;
|
1197
|
+
this.packPromise = undefined;
|
1116
1198
|
}
|
1117
1199
|
}
|
1118
1200
|
|
package/lib/config/defaults.js
CHANGED
@@ -117,6 +117,7 @@ const A = (obj, prop, factory) => {
|
|
117
117
|
*/
|
118
118
|
const applyWebpackOptionsBaseDefaults = options => {
|
119
119
|
F(options, "context", () => process.cwd());
|
120
|
+
applyInfrastructureLoggingDefaults(options.infrastructureLogging);
|
120
121
|
};
|
121
122
|
|
122
123
|
/**
|
@@ -163,7 +164,8 @@ const applyWebpackOptionsDefaults = options => {
|
|
163
164
|
);
|
164
165
|
applyCacheDefaults(options.cache, {
|
165
166
|
name: name || "default",
|
166
|
-
mode: mode || "production"
|
167
|
+
mode: mode || "production",
|
168
|
+
development
|
167
169
|
});
|
168
170
|
const cache = !!options.cache;
|
169
171
|
|
@@ -234,8 +236,6 @@ const applyWebpackOptionsDefaults = options => {
|
|
234
236
|
getResolveLoaderDefaults({ cache }),
|
235
237
|
options.resolveLoader
|
236
238
|
);
|
237
|
-
|
238
|
-
applyInfrastructureLoggingDefaults(options.infrastructureLogging);
|
239
239
|
};
|
240
240
|
|
241
241
|
/**
|
@@ -254,9 +254,10 @@ const applyExperimentsDefaults = experiments => {
|
|
254
254
|
* @param {Object} options options
|
255
255
|
* @param {string} options.name name
|
256
256
|
* @param {string} options.mode mode
|
257
|
+
* @param {boolean} options.development is development mode
|
257
258
|
* @returns {void}
|
258
259
|
*/
|
259
|
-
const applyCacheDefaults = (cache, { name, mode }) => {
|
260
|
+
const applyCacheDefaults = (cache, { name, mode, development }) => {
|
260
261
|
if (cache === false) return;
|
261
262
|
switch (cache.type) {
|
262
263
|
case "filesystem":
|
@@ -294,10 +295,15 @@ const applyCacheDefaults = (cache, { name, mode }) => {
|
|
294
295
|
D(cache, "store", "pack");
|
295
296
|
D(cache, "idleTimeout", 60000);
|
296
297
|
D(cache, "idleTimeoutForInitialStore", 0);
|
298
|
+
D(cache, "maxMemoryGenerations", development ? 10 : Infinity);
|
299
|
+
D(cache, "maxAge", 1000 * 60 * 60 * 24 * 60); // 1 month
|
297
300
|
D(cache.buildDependencies, "defaultWebpack", [
|
298
301
|
path.resolve(__dirname, "..") + path.sep
|
299
302
|
]);
|
300
303
|
break;
|
304
|
+
case "memory":
|
305
|
+
D(cache, "maxGenerations", Infinity);
|
306
|
+
break;
|
301
307
|
}
|
302
308
|
};
|
303
309
|
|
@@ -1070,8 +1076,14 @@ const getResolveLoaderDefaults = ({ cache }) => {
|
|
1070
1076
|
* @returns {void}
|
1071
1077
|
*/
|
1072
1078
|
const applyInfrastructureLoggingDefaults = infrastructureLogging => {
|
1079
|
+
F(infrastructureLogging, "stream", () => process.stderr);
|
1080
|
+
const tty =
|
1081
|
+
/** @type {any} */ (infrastructureLogging.stream).isTTY &&
|
1082
|
+
process.env.TERM !== "dumb";
|
1073
1083
|
D(infrastructureLogging, "level", "info");
|
1074
1084
|
D(infrastructureLogging, "debug", false);
|
1085
|
+
D(infrastructureLogging, "colors", tty);
|
1086
|
+
D(infrastructureLogging, "appendOnly", !tty);
|
1075
1087
|
};
|
1076
1088
|
|
1077
1089
|
exports.applyWebpackOptionsBaseDefaults = applyWebpackOptionsBaseDefaults;
|