@atlaspack/core 2.17.2 → 2.17.4
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.
- package/CHANGELOG.md +50 -0
- package/lib/Atlaspack.js +10 -2
- package/lib/PackagerRunner.js +42 -8
- package/lib/RequestTracker.js +288 -88
- package/lib/UncommittedAsset.js +17 -0
- package/lib/atlaspack-v3/worker/worker.js +8 -0
- package/lib/public/BundleGraph.js +21 -5
- package/lib/public/Config.js +28 -0
- package/lib/requests/AssetGraphRequest.js +13 -1
- package/lib/requests/BundleGraphRequest.js +13 -1
- package/lib/requests/WriteBundleRequest.js +11 -2
- package/lib/resolveOptions.js +4 -2
- package/package.json +18 -14
- package/src/Atlaspack.js +13 -5
- package/src/PackagerRunner.js +60 -9
- package/src/RequestTracker.js +491 -137
- package/src/UncommittedAsset.js +16 -1
- package/src/atlaspack-v3/worker/compat/plugin-config.js +9 -5
- package/src/atlaspack-v3/worker/worker.js +7 -0
- package/src/public/BundleGraph.js +22 -5
- package/src/public/Config.js +39 -5
- package/src/requests/AssetGraphRequest.js +13 -3
- package/src/requests/BundleGraphRequest.js +13 -3
- package/src/requests/WriteBundleRequest.js +9 -2
- package/src/resolveOptions.js +4 -2
- package/test/RequestTracker.test.js +115 -3
- package/test/test-utils.js +1 -7
package/lib/RequestTracker.js
CHANGED
|
@@ -6,9 +6,13 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.RequestGraph = void 0;
|
|
7
7
|
exports.cleanUpOrphans = cleanUpOrphans;
|
|
8
8
|
exports.default = void 0;
|
|
9
|
+
exports.getBiggestFSEventsInvalidations = getBiggestFSEventsInvalidations;
|
|
9
10
|
exports.getWatcherOptions = getWatcherOptions;
|
|
11
|
+
exports.invalidateRequestGraph = invalidateRequestGraph;
|
|
12
|
+
exports.invalidateRequestGraphFSEvents = invalidateRequestGraphFSEvents;
|
|
10
13
|
exports.readAndDeserializeRequestGraph = readAndDeserializeRequestGraph;
|
|
11
14
|
exports.requestTypes = exports.requestGraphEdgeTypes = void 0;
|
|
15
|
+
exports.runInvalidation = runInvalidation;
|
|
12
16
|
function _assert() {
|
|
13
17
|
const data = _interopRequireWildcard(require("assert"));
|
|
14
18
|
_assert = function () {
|
|
@@ -84,6 +88,13 @@ var _projectPath = require("./projectPath");
|
|
|
84
88
|
var _ReporterRunner = require("./ReporterRunner");
|
|
85
89
|
var _ConfigRequest = require("./requests/ConfigRequest");
|
|
86
90
|
var _utils2 = require("./utils");
|
|
91
|
+
function _perf_hooks() {
|
|
92
|
+
const data = require("perf_hooks");
|
|
93
|
+
_perf_hooks = function () {
|
|
94
|
+
return data;
|
|
95
|
+
};
|
|
96
|
+
return data;
|
|
97
|
+
}
|
|
87
98
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
88
99
|
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
89
100
|
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
@@ -279,6 +290,12 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
279
290
|
// If the node is invalidated, the cached request chunk on disk needs to be re-written
|
|
280
291
|
this.removeCachedRequestChunkForNode(nodeId);
|
|
281
292
|
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Nodes that are invalidated on start-up, such as JavaScript babel configuration files which are
|
|
296
|
+
* imported when the build kicks-off and might doing arbitrary work such as reading from the file
|
|
297
|
+
* system.
|
|
298
|
+
*/
|
|
282
299
|
invalidateUnpredictableNodes() {
|
|
283
300
|
for (let nodeId of this.unpredicatableNodeIds) {
|
|
284
301
|
let node = (0, _nullthrows().default)(this.getNode(nodeId));
|
|
@@ -286,6 +303,10 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
286
303
|
this.invalidateNode(nodeId, _constants.STARTUP);
|
|
287
304
|
}
|
|
288
305
|
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Effectively uncacheable nodes.
|
|
309
|
+
*/
|
|
289
310
|
invalidateOnBuildNodes() {
|
|
290
311
|
for (let nodeId of this.invalidateOnBuildNodeIds) {
|
|
291
312
|
let node = (0, _nullthrows().default)(this.getNode(nodeId));
|
|
@@ -293,29 +314,45 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
293
314
|
this.invalidateNode(nodeId, _constants.STARTUP);
|
|
294
315
|
}
|
|
295
316
|
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Nodes invalidated by environment changes, corresponds to `env: ...` inputs.
|
|
320
|
+
*/
|
|
296
321
|
invalidateEnvNodes(env) {
|
|
322
|
+
const invalidatedKeys = [];
|
|
297
323
|
for (let nodeId of this.envNodeIds) {
|
|
298
324
|
let node = (0, _nullthrows().default)(this.getNode(nodeId));
|
|
299
325
|
(0, _assert().default)(node.type === ENV);
|
|
300
|
-
|
|
326
|
+
const key = keyFromEnvContentKey(node.id);
|
|
327
|
+
if (env[key] !== node.value) {
|
|
328
|
+
invalidatedKeys.push(key);
|
|
301
329
|
let parentNodes = this.getNodeIdsConnectedTo(nodeId, requestGraphEdgeTypes.invalidated_by_update);
|
|
302
330
|
for (let parentNode of parentNodes) {
|
|
303
331
|
this.invalidateNode(parentNode, _constants.ENV_CHANGE);
|
|
304
332
|
}
|
|
305
333
|
}
|
|
306
334
|
}
|
|
335
|
+
return invalidatedKeys;
|
|
307
336
|
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Nodes invalidated by option changes.
|
|
340
|
+
*/
|
|
308
341
|
invalidateOptionNodes(options) {
|
|
342
|
+
const invalidatedKeys = [];
|
|
309
343
|
for (let nodeId of this.optionNodeIds) {
|
|
310
344
|
let node = (0, _nullthrows().default)(this.getNode(nodeId));
|
|
311
345
|
(0, _assert().default)(node.type === OPTION);
|
|
312
|
-
|
|
346
|
+
const key = keyFromOptionContentKey(node.id);
|
|
347
|
+
if ((0, _utils2.hashFromOption)(options[key]) !== node.hash) {
|
|
348
|
+
invalidatedKeys.push(key);
|
|
313
349
|
let parentNodes = this.getNodeIdsConnectedTo(nodeId, requestGraphEdgeTypes.invalidated_by_update);
|
|
314
350
|
for (let parentNode of parentNodes) {
|
|
315
351
|
this.invalidateNode(parentNode, _constants.OPTION_CHANGE);
|
|
316
352
|
}
|
|
317
353
|
}
|
|
318
354
|
}
|
|
355
|
+
return invalidatedKeys;
|
|
319
356
|
}
|
|
320
357
|
invalidateOnConfigKeyChange(requestNodeId, filePath, configKey, contentHash) {
|
|
321
358
|
let configKeyNodeId = this.addNode(nodeFromConfigKey(filePath, configKey, contentHash));
|
|
@@ -556,10 +593,12 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
556
593
|
aboveCache.set(fileNameNodeId, above);
|
|
557
594
|
return above;
|
|
558
595
|
};
|
|
596
|
+
const invalidationsByPath = new Map();
|
|
559
597
|
for (let {
|
|
560
598
|
path: _path,
|
|
561
599
|
type
|
|
562
600
|
} of events) {
|
|
601
|
+
const invalidationsBefore = this.getInvalidNodeCount();
|
|
563
602
|
if (!enableOptimization && process.env.ATLASPACK_DISABLE_CACHE_TIMEOUT !== 'true' && ++count === 256) {
|
|
564
603
|
let duration = Date.now() - startTime;
|
|
565
604
|
predictedTime = duration * (events.length >> 8);
|
|
@@ -596,7 +635,10 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
596
635
|
this.invalidNodeIds.add(id);
|
|
597
636
|
}
|
|
598
637
|
}
|
|
599
|
-
return
|
|
638
|
+
return {
|
|
639
|
+
didInvalidate: true,
|
|
640
|
+
invalidationsByPath: new Map()
|
|
641
|
+
};
|
|
600
642
|
}
|
|
601
643
|
|
|
602
644
|
// sometimes mac os reports update events as create events.
|
|
@@ -671,6 +713,8 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
671
713
|
}
|
|
672
714
|
}
|
|
673
715
|
}
|
|
716
|
+
const invalidationsAfter = this.getInvalidNodeCount();
|
|
717
|
+
invalidationsByPath.set(_path, (invalidationsByPath.get(_path) ?? 0) + (invalidationsAfter - invalidationsBefore));
|
|
674
718
|
}
|
|
675
719
|
if ((0, _featureFlags().getFeatureFlag)('fixQuadraticCacheInvalidation')) {
|
|
676
720
|
cleanUpOrphans(this);
|
|
@@ -688,7 +732,10 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
688
732
|
numberOfInvalidatedNodes: invalidatedNodes.size
|
|
689
733
|
}
|
|
690
734
|
});
|
|
691
|
-
return
|
|
735
|
+
return {
|
|
736
|
+
didInvalidate,
|
|
737
|
+
invalidationsByPath
|
|
738
|
+
};
|
|
692
739
|
}
|
|
693
740
|
hasCachedRequestChunk(index) {
|
|
694
741
|
return this.cachedRequestChunks.has(index);
|
|
@@ -699,6 +746,13 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
699
746
|
removeCachedRequestChunkForNode(nodeId) {
|
|
700
747
|
this.cachedRequestChunks.delete(Math.floor(nodeId / this.nodesPerBlob));
|
|
701
748
|
}
|
|
749
|
+
|
|
750
|
+
/**
|
|
751
|
+
* Returns the number of invalidated nodes in the graph.
|
|
752
|
+
*/
|
|
753
|
+
getInvalidNodeCount() {
|
|
754
|
+
return this.invalidNodeIds.size;
|
|
755
|
+
}
|
|
702
756
|
}
|
|
703
757
|
exports.RequestGraph = RequestGraph;
|
|
704
758
|
class RequestTracker {
|
|
@@ -944,84 +998,85 @@ class RequestTracker {
|
|
|
944
998
|
return result;
|
|
945
999
|
}
|
|
946
1000
|
}
|
|
947
|
-
await runCacheImprovements(async cache => {
|
|
948
|
-
await cache.getNativeRef().startWriteTransaction();
|
|
949
|
-
}, () => Promise.resolve());
|
|
950
1001
|
let cacheKey = getCacheKey(this.options);
|
|
951
|
-
let requestGraphKey = `requestGraph-${cacheKey}`;
|
|
1002
|
+
let requestGraphKey = (0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements') ? `${cacheKey}/RequestGraph` : `requestGraph-${cacheKey}`;
|
|
1003
|
+
let snapshotKey = (0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements') ? `${cacheKey}/snapshot` : `snapshot-${cacheKey}`;
|
|
952
1004
|
if (this.options.shouldDisableCache) {
|
|
953
1005
|
return;
|
|
954
1006
|
}
|
|
955
1007
|
let total = 0;
|
|
956
|
-
(
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
size: this.graph.nodes.length
|
|
961
|
-
});
|
|
962
|
-
let serialisedGraph = this.graph.serialize();
|
|
963
|
-
|
|
964
|
-
// Delete an existing request graph cache, to prevent invalid states
|
|
965
|
-
await this.options.cache.deleteLargeBlob(requestGraphKey);
|
|
966
|
-
const serialiseAndSet = async (key, contents) => {
|
|
967
|
-
if (signal !== null && signal !== void 0 && signal.aborted) {
|
|
968
|
-
throw new Error('Serialization was aborted');
|
|
969
|
-
}
|
|
970
|
-
await runCacheImprovements(cache => {
|
|
971
|
-
(0, _logger().instrument)(`cache.put(${key})`, () => {
|
|
972
|
-
cache.getNativeRef().putNoConfirm(key, (0, _buildCache().serialize)(contents));
|
|
973
|
-
});
|
|
974
|
-
return Promise.resolve();
|
|
975
|
-
}, async () => {
|
|
976
|
-
await this.options.cache.setLargeBlob(key, (0, _buildCache().serialize)(contents), signal ? {
|
|
977
|
-
signal: signal
|
|
978
|
-
} : undefined);
|
|
979
|
-
});
|
|
980
|
-
total += 1;
|
|
1008
|
+
await runCacheImprovements(async cache => {
|
|
1009
|
+
await cache.getNativeRef().startWriteTransaction();
|
|
1010
|
+
}, () => Promise.resolve());
|
|
1011
|
+
try {
|
|
981
1012
|
(0, _ReporterRunner.report)({
|
|
982
1013
|
type: 'cache',
|
|
983
|
-
phase: '
|
|
1014
|
+
phase: 'start',
|
|
984
1015
|
total,
|
|
985
1016
|
size: this.graph.nodes.length
|
|
986
1017
|
});
|
|
987
|
-
|
|
988
|
-
let queue = new (_utils().PromiseQueue)({
|
|
989
|
-
maxConcurrent: 32
|
|
990
|
-
});
|
|
1018
|
+
let serialisedGraph = this.graph.serialize();
|
|
991
1019
|
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
1020
|
+
// Delete an existing request graph cache, to prevent invalid states
|
|
1021
|
+
await this.options.cache.deleteLargeBlob(requestGraphKey);
|
|
1022
|
+
const serialiseAndSet = async (key, contents) => {
|
|
1023
|
+
if (signal !== null && signal !== void 0 && signal.aborted) {
|
|
1024
|
+
throw new Error('Serialization was aborted');
|
|
1025
|
+
}
|
|
1026
|
+
await runCacheImprovements(cache => {
|
|
1027
|
+
(0, _logger().instrument)(`RequestTracker::writeToCache::cache.put(${key})`, () => {
|
|
1028
|
+
cache.getNativeRef().putNoConfirm(key, (0, _buildCache().serialize)(contents));
|
|
1029
|
+
});
|
|
1030
|
+
return Promise.resolve();
|
|
1031
|
+
}, async () => {
|
|
1032
|
+
await this.options.cache.setLargeBlob(key, (0, _buildCache().serialize)(contents), signal ? {
|
|
1033
|
+
signal: signal
|
|
1034
|
+
} : undefined);
|
|
1035
|
+
});
|
|
1036
|
+
total += 1;
|
|
1037
|
+
(0, _ReporterRunner.report)({
|
|
1038
|
+
type: 'cache',
|
|
1039
|
+
phase: 'write',
|
|
1040
|
+
total,
|
|
1041
|
+
size: this.graph.nodes.length
|
|
1042
|
+
});
|
|
1043
|
+
};
|
|
1044
|
+
let queue = new (_utils().PromiseQueue)({
|
|
1045
|
+
maxConcurrent: 32
|
|
1046
|
+
});
|
|
999
1047
|
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1048
|
+
// Preallocating a sparse array is faster than pushing when N is high enough
|
|
1049
|
+
let cacheableNodes = new Array(serialisedGraph.nodes.length);
|
|
1050
|
+
for (let i = 0; i < serialisedGraph.nodes.length; i += 1) {
|
|
1051
|
+
let node = serialisedGraph.nodes[i];
|
|
1052
|
+
let resultCacheKey = node === null || node === void 0 ? void 0 : node.resultCacheKey;
|
|
1053
|
+
if ((node === null || node === void 0 ? void 0 : node.type) === REQUEST && resultCacheKey != null && (node === null || node === void 0 ? void 0 : node.result) != null) {
|
|
1054
|
+
queue.add(() => serialiseAndSet(resultCacheKey, node.result));
|
|
1055
|
+
|
|
1056
|
+
// eslint-disable-next-line no-unused-vars
|
|
1057
|
+
let {
|
|
1058
|
+
result: _,
|
|
1059
|
+
...newNode
|
|
1060
|
+
} = node;
|
|
1061
|
+
cacheableNodes[i] = newNode;
|
|
1062
|
+
} else {
|
|
1063
|
+
cacheableNodes[i] = node;
|
|
1064
|
+
}
|
|
1008
1065
|
}
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
}
|
|
1066
|
+
let nodeCountsPerBlob = [];
|
|
1067
|
+
for (let i = 0; i * this.graph.nodesPerBlob < cacheableNodes.length; i += 1) {
|
|
1068
|
+
let nodesStartIndex = i * this.graph.nodesPerBlob;
|
|
1069
|
+
let nodesEndIndex = Math.min((i + 1) * this.graph.nodesPerBlob, cacheableNodes.length);
|
|
1070
|
+
nodeCountsPerBlob.push(nodesEndIndex - nodesStartIndex);
|
|
1071
|
+
if (!this.graph.hasCachedRequestChunk(i)) {
|
|
1072
|
+
// We assume the request graph nodes are immutable and won't change
|
|
1073
|
+
let nodesToCache = cacheableNodes.slice(nodesStartIndex, nodesEndIndex);
|
|
1074
|
+
queue.add(() => serialiseAndSet(getRequestGraphNodeKey(i, cacheKey), nodesToCache).then(() => {
|
|
1075
|
+
// Succeeded in writing to disk, save that we have completed this chunk
|
|
1076
|
+
this.graph.setCachedRequestChunk(i);
|
|
1077
|
+
}));
|
|
1078
|
+
}
|
|
1022
1079
|
}
|
|
1023
|
-
}
|
|
1024
|
-
try {
|
|
1025
1080
|
await queue.run();
|
|
1026
1081
|
|
|
1027
1082
|
// Set the request graph after the queue is flushed to avoid writing an invalid state
|
|
@@ -1030,7 +1085,7 @@ class RequestTracker {
|
|
|
1030
1085
|
nodeCountsPerBlob,
|
|
1031
1086
|
nodes: undefined
|
|
1032
1087
|
});
|
|
1033
|
-
await runCacheImprovements(() => serialiseAndSet(
|
|
1088
|
+
await runCacheImprovements(() => serialiseAndSet(`${cacheKey}/cache_metadata`, {
|
|
1034
1089
|
version: _constants.ATLASPACK_VERSION,
|
|
1035
1090
|
entries: this.options.entries,
|
|
1036
1091
|
mode: this.options.mode,
|
|
@@ -1038,15 +1093,16 @@ class RequestTracker {
|
|
|
1038
1093
|
watchBackend: this.options.watchBackend
|
|
1039
1094
|
}), () => Promise.resolve());
|
|
1040
1095
|
let opts = getWatcherOptions(this.options);
|
|
1041
|
-
let snapshotPath = _path2().default.join(this.options.cacheDir,
|
|
1096
|
+
let snapshotPath = _path2().default.join(this.options.cacheDir, snapshotKey + '.txt');
|
|
1042
1097
|
await this.options.outputFS.writeSnapshot(this.options.watchDir, snapshotPath, opts);
|
|
1043
1098
|
} catch (err) {
|
|
1044
1099
|
// If we have aborted, ignore the error and continue
|
|
1045
1100
|
if (!(signal !== null && signal !== void 0 && signal.aborted)) throw err;
|
|
1101
|
+
} finally {
|
|
1102
|
+
await runCacheImprovements(async cache => {
|
|
1103
|
+
await cache.getNativeRef().commitWriteTransaction();
|
|
1104
|
+
}, () => Promise.resolve());
|
|
1046
1105
|
}
|
|
1047
|
-
await runCacheImprovements(async cache => {
|
|
1048
|
-
await cache.getNativeRef().commitWriteTransaction();
|
|
1049
|
-
}, () => Promise.resolve());
|
|
1050
1106
|
(0, _ReporterRunner.report)({
|
|
1051
1107
|
type: 'cache',
|
|
1052
1108
|
phase: 'end',
|
|
@@ -1083,17 +1139,30 @@ function getWatcherOptions({
|
|
|
1083
1139
|
};
|
|
1084
1140
|
}
|
|
1085
1141
|
function getCacheKey(options) {
|
|
1142
|
+
if ((0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements')) {
|
|
1143
|
+
const hash = (0, _rust().hashString)(`${_constants.ATLASPACK_VERSION}:${JSON.stringify(options.entries)}:${options.mode}:${options.shouldBuildLazily ? 'lazy' : 'eager'}:${options.watchBackend ?? ''}`);
|
|
1144
|
+
return `RequestTracker/${_constants.ATLASPACK_VERSION}/${hash}`;
|
|
1145
|
+
}
|
|
1086
1146
|
return (0, _rust().hashString)(`${_constants.ATLASPACK_VERSION}:${JSON.stringify(options.entries)}:${options.mode}:${options.shouldBuildLazily ? 'lazy' : 'eager'}:${options.watchBackend ?? ''}`);
|
|
1087
1147
|
}
|
|
1088
1148
|
function getRequestGraphNodeKey(index, cacheKey) {
|
|
1149
|
+
if ((0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements')) {
|
|
1150
|
+
return `${cacheKey}/RequestGraph/nodes/${index}`;
|
|
1151
|
+
}
|
|
1089
1152
|
return `requestGraph-nodes-${index}-${cacheKey}`;
|
|
1090
1153
|
}
|
|
1091
1154
|
async function readAndDeserializeRequestGraph(cache, requestGraphKey, cacheKey) {
|
|
1092
1155
|
let bufferLength = 0;
|
|
1093
1156
|
const getAndDeserialize = async key => {
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1157
|
+
if ((0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements')) {
|
|
1158
|
+
const buffer = await cache.getBlob(key);
|
|
1159
|
+
bufferLength += Buffer.byteLength(buffer);
|
|
1160
|
+
return (0, _buildCache().deserialize)(buffer);
|
|
1161
|
+
} else {
|
|
1162
|
+
const buffer = await cache.getLargeBlob(key);
|
|
1163
|
+
bufferLength += Buffer.byteLength(buffer);
|
|
1164
|
+
return (0, _buildCache().deserialize)(buffer);
|
|
1165
|
+
}
|
|
1097
1166
|
};
|
|
1098
1167
|
let serializedRequestGraph = await getAndDeserialize(requestGraphKey);
|
|
1099
1168
|
let nodePromises = serializedRequestGraph.nodeCountsPerBlob.map(async (nodesCount, i) => {
|
|
@@ -1115,19 +1184,30 @@ async function loadRequestGraph(options) {
|
|
|
1115
1184
|
return new RequestGraph();
|
|
1116
1185
|
}
|
|
1117
1186
|
let cacheKey = getCacheKey(options);
|
|
1118
|
-
let requestGraphKey = `requestGraph-${cacheKey}`;
|
|
1187
|
+
let requestGraphKey = (0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements') ? `${cacheKey}/RequestGraph` : `requestGraph-${cacheKey}`;
|
|
1119
1188
|
let timeout;
|
|
1120
|
-
const snapshotKey = `snapshot-${cacheKey}`;
|
|
1189
|
+
const snapshotKey = (0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements') ? `${cacheKey}/snapshot` : `snapshot-${cacheKey}`;
|
|
1121
1190
|
const snapshotPath = _path2().default.join(options.cacheDir, snapshotKey + '.txt');
|
|
1191
|
+
const commonMeta = {
|
|
1192
|
+
cacheKey,
|
|
1193
|
+
snapshotKey,
|
|
1194
|
+
cacheKeyOptions: {
|
|
1195
|
+
version: _constants.ATLASPACK_VERSION,
|
|
1196
|
+
entries: options.entries,
|
|
1197
|
+
mode: options.mode,
|
|
1198
|
+
shouldBuildLazily: options.shouldBuildLazily,
|
|
1199
|
+
watchBackend: options.watchBackend
|
|
1200
|
+
}
|
|
1201
|
+
};
|
|
1122
1202
|
_logger().default.verbose({
|
|
1123
1203
|
origin: '@atlaspack/core',
|
|
1124
1204
|
message: 'Loading request graph',
|
|
1125
1205
|
meta: {
|
|
1126
|
-
|
|
1127
|
-
snapshotKey
|
|
1206
|
+
...commonMeta
|
|
1128
1207
|
}
|
|
1129
1208
|
});
|
|
1130
|
-
|
|
1209
|
+
const hasRequestGraphInCache = (0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements') ? await options.cache.has(requestGraphKey) : await options.cache.hasLargeBlob(requestGraphKey);
|
|
1210
|
+
if (hasRequestGraphInCache) {
|
|
1131
1211
|
try {
|
|
1132
1212
|
let {
|
|
1133
1213
|
requestGraph
|
|
@@ -1146,16 +1226,29 @@ async function loadRequestGraph(options) {
|
|
|
1146
1226
|
origin: '@atlaspack/core',
|
|
1147
1227
|
message: `File system event count: ${events.length}`,
|
|
1148
1228
|
meta: {
|
|
1229
|
+
...commonMeta,
|
|
1149
1230
|
trackableEvent: 'watcher_events_count',
|
|
1150
1231
|
watcherEventCount: events.length,
|
|
1151
1232
|
duration: Date.now() - startTime
|
|
1152
1233
|
}
|
|
1153
1234
|
});
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1235
|
+
if ((0, _featureFlags().getFeatureFlag)('verboseRequestInvalidationStats')) {
|
|
1236
|
+
const invalidationStats = await invalidateRequestGraph(requestGraph, options, events);
|
|
1237
|
+
_logger().default.verbose({
|
|
1238
|
+
origin: '@atlaspack/core',
|
|
1239
|
+
message: 'Request track loaded from cache',
|
|
1240
|
+
meta: {
|
|
1241
|
+
...commonMeta,
|
|
1242
|
+
trackableEvent: 'request_tracker_cache_key_hit',
|
|
1243
|
+
invalidationStats
|
|
1244
|
+
}
|
|
1245
|
+
});
|
|
1246
|
+
} else {
|
|
1247
|
+
requestGraph.invalidateUnpredictableNodes();
|
|
1248
|
+
requestGraph.invalidateOnBuildNodes();
|
|
1249
|
+
requestGraph.invalidateEnvNodes(options.env);
|
|
1250
|
+
requestGraph.invalidateOptionNodes(options);
|
|
1251
|
+
}
|
|
1159
1252
|
return requestGraph;
|
|
1160
1253
|
} catch (e) {
|
|
1161
1254
|
// Prevent logging fs events took too long warning
|
|
@@ -1170,12 +1263,104 @@ async function loadRequestGraph(options) {
|
|
|
1170
1263
|
origin: '@atlaspack/core',
|
|
1171
1264
|
message: 'Cache entry for request tracker was not found, initializing a clean cache.',
|
|
1172
1265
|
meta: {
|
|
1173
|
-
|
|
1174
|
-
|
|
1266
|
+
...commonMeta,
|
|
1267
|
+
trackableEvent: 'request_tracker_cache_key_miss'
|
|
1175
1268
|
}
|
|
1176
1269
|
});
|
|
1177
1270
|
return new RequestGraph();
|
|
1178
1271
|
}
|
|
1272
|
+
|
|
1273
|
+
/**
|
|
1274
|
+
* A wrapper around an invalidation type / method
|
|
1275
|
+
*/
|
|
1276
|
+
|
|
1277
|
+
/**
|
|
1278
|
+
* Details about an invalidation.
|
|
1279
|
+
*
|
|
1280
|
+
* If this is a fs events invalidation, this key will contain statistics about invalidations
|
|
1281
|
+
* by path.
|
|
1282
|
+
*
|
|
1283
|
+
* If this is a env or option invalidation, this key will contain the list of changed environment
|
|
1284
|
+
* variables or options.
|
|
1285
|
+
*/
|
|
1286
|
+
|
|
1287
|
+
/**
|
|
1288
|
+
* Number of invalidations for a given file-system event.
|
|
1289
|
+
*/
|
|
1290
|
+
|
|
1291
|
+
/**
|
|
1292
|
+
* Information about a certain cache invalidation type.
|
|
1293
|
+
*/
|
|
1294
|
+
|
|
1295
|
+
/**
|
|
1296
|
+
* Respond to unpredictable, build, environment changes, option changes and file-system events
|
|
1297
|
+
* invalidating RequestGraph nodes.
|
|
1298
|
+
*
|
|
1299
|
+
* Returns the count of nodes invalidated by each invalidation type.
|
|
1300
|
+
*/
|
|
1301
|
+
async function invalidateRequestGraph(requestGraph, options, events) {
|
|
1302
|
+
const invalidationFns = [{
|
|
1303
|
+
key: 'unpredictable',
|
|
1304
|
+
fn: () => requestGraph.invalidateUnpredictableNodes()
|
|
1305
|
+
}, {
|
|
1306
|
+
key: 'onBuild',
|
|
1307
|
+
fn: () => requestGraph.invalidateOnBuildNodes()
|
|
1308
|
+
}, {
|
|
1309
|
+
key: 'env',
|
|
1310
|
+
fn: () => requestGraph.invalidateEnvNodes(options.env)
|
|
1311
|
+
}, {
|
|
1312
|
+
key: 'option',
|
|
1313
|
+
fn: () => requestGraph.invalidateOptionNodes(options)
|
|
1314
|
+
}, {
|
|
1315
|
+
key: 'fsEvents',
|
|
1316
|
+
fn: () => invalidateRequestGraphFSEvents(requestGraph, options, events)
|
|
1317
|
+
}];
|
|
1318
|
+
const invalidations = [];
|
|
1319
|
+
for (const invalidation of invalidationFns) {
|
|
1320
|
+
invalidations.push(await runInvalidation(requestGraph, invalidation));
|
|
1321
|
+
}
|
|
1322
|
+
const invalidatedCount = invalidations.reduce((acc, invalidation) => acc + invalidation.count, 0);
|
|
1323
|
+
const requestCount = requestGraph.nodes.reduce((acc, node) => acc + ((node === null || node === void 0 ? void 0 : node.type) === REQUEST ? 1 : 0), 0);
|
|
1324
|
+
const nodeCount = requestGraph.nodes.length;
|
|
1325
|
+
return {
|
|
1326
|
+
invalidations,
|
|
1327
|
+
nodeCount,
|
|
1328
|
+
requestCount,
|
|
1329
|
+
invalidatedCount,
|
|
1330
|
+
nodeInvalidationRatio: invalidatedCount / nodeCount,
|
|
1331
|
+
requestInvalidationRatio: invalidatedCount / requestCount
|
|
1332
|
+
};
|
|
1333
|
+
}
|
|
1334
|
+
/**
|
|
1335
|
+
* Invalidate the request graph based on file-system events.
|
|
1336
|
+
*
|
|
1337
|
+
* Returns statistics about the invalidations.
|
|
1338
|
+
*/
|
|
1339
|
+
async function invalidateRequestGraphFSEvents(requestGraph, options, events) {
|
|
1340
|
+
const {
|
|
1341
|
+
invalidationsByPath
|
|
1342
|
+
} = await requestGraph.respondToFSEvents(options.unstableFileInvalidations || events, options, 10000, true);
|
|
1343
|
+
const biggestInvalidations = getBiggestFSEventsInvalidations(invalidationsByPath);
|
|
1344
|
+
return {
|
|
1345
|
+
biggestInvalidations
|
|
1346
|
+
};
|
|
1347
|
+
}
|
|
1348
|
+
/**
|
|
1349
|
+
* Runs an invalidation function and reports metrics.
|
|
1350
|
+
*/
|
|
1351
|
+
async function runInvalidation(requestGraph, invalidationFn) {
|
|
1352
|
+
const start = _perf_hooks().performance.now();
|
|
1353
|
+
const startInvalidationCount = requestGraph.getInvalidNodeCount();
|
|
1354
|
+
const result = await invalidationFn.fn();
|
|
1355
|
+
const count = requestGraph.getInvalidNodeCount() - startInvalidationCount;
|
|
1356
|
+
const duration = _perf_hooks().performance.now() - start;
|
|
1357
|
+
return {
|
|
1358
|
+
key: invalidationFn.key,
|
|
1359
|
+
count,
|
|
1360
|
+
detail: result ?? null,
|
|
1361
|
+
duration
|
|
1362
|
+
};
|
|
1363
|
+
}
|
|
1179
1364
|
function logErrorOnBailout(options, snapshotPath, e) {
|
|
1180
1365
|
if (e.message && e.message.includes('invalid clockspec')) {
|
|
1181
1366
|
const snapshotContents = options.inputFS.readFileSync(snapshotPath, 'utf-8');
|
|
@@ -1215,4 +1400,19 @@ function cleanUpOrphans(graph) {
|
|
|
1215
1400
|
}
|
|
1216
1401
|
});
|
|
1217
1402
|
return removedNodeIds;
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
/**
|
|
1406
|
+
* Returns paths that invalidated the most nodes
|
|
1407
|
+
*/
|
|
1408
|
+
function getBiggestFSEventsInvalidations(invalidationsByPath, limit = 10) {
|
|
1409
|
+
const invalidations = [];
|
|
1410
|
+
for (const [path, count] of invalidationsByPath) {
|
|
1411
|
+
invalidations.push({
|
|
1412
|
+
path,
|
|
1413
|
+
count
|
|
1414
|
+
});
|
|
1415
|
+
}
|
|
1416
|
+
invalidations.sort((a, b) => b.count - a.count);
|
|
1417
|
+
return invalidations.slice(0, limit);
|
|
1218
1418
|
}
|
package/lib/UncommittedAsset.js
CHANGED
|
@@ -53,6 +53,13 @@ var _assetUtils = require("./assetUtils");
|
|
|
53
53
|
var _types = require("./types");
|
|
54
54
|
var _utils2 = require("./utils");
|
|
55
55
|
var _projectPath = require("./projectPath");
|
|
56
|
+
function _featureFlags() {
|
|
57
|
+
const data = require("@atlaspack/feature-flags");
|
|
58
|
+
_featureFlags = function () {
|
|
59
|
+
return data;
|
|
60
|
+
};
|
|
61
|
+
return data;
|
|
62
|
+
}
|
|
56
63
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
57
64
|
class UncommittedAsset {
|
|
58
65
|
constructor({
|
|
@@ -133,6 +140,8 @@ class UncommittedAsset {
|
|
|
133
140
|
hash = (0, _rust().hashBuffer)(content);
|
|
134
141
|
size = content.length;
|
|
135
142
|
}
|
|
143
|
+
|
|
144
|
+
// Maybe we should just store this in a file instead of LMDB
|
|
136
145
|
await this.options.cache.setBlob(contentKey, content);
|
|
137
146
|
return {
|
|
138
147
|
size,
|
|
@@ -184,6 +193,10 @@ class UncommittedAsset {
|
|
|
184
193
|
this.content = buffer;
|
|
185
194
|
this.clearAST();
|
|
186
195
|
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* @deprecated This has been broken on any cache other than FSCache for a long time.
|
|
199
|
+
*/
|
|
187
200
|
setStream(stream) {
|
|
188
201
|
this.content = stream;
|
|
189
202
|
this.clearAST();
|
|
@@ -248,6 +261,10 @@ class UncommittedAsset {
|
|
|
248
261
|
this.value.astGenerator = null;
|
|
249
262
|
}
|
|
250
263
|
getCacheKey(key) {
|
|
264
|
+
if ((0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements')) {
|
|
265
|
+
const filePath = (0, _projectPath.fromProjectPathRelative)(this.value.filePath);
|
|
266
|
+
return `Asset/${_constants.ATLASPACK_VERSION}/${filePath}/${this.value.id}/${key}`;
|
|
267
|
+
}
|
|
251
268
|
return (0, _rust().hashString)(_constants.ATLASPACK_VERSION + key + this.value.id);
|
|
252
269
|
}
|
|
253
270
|
addDependency(opts) {
|
|
@@ -32,6 +32,13 @@ var _Dependency = _interopRequireWildcard(require("./Dependency"));
|
|
|
32
32
|
var _Target = require("./Target");
|
|
33
33
|
var _utils = require("../utils");
|
|
34
34
|
var _BundleGroup = _interopRequireWildcard(require("./BundleGroup"));
|
|
35
|
+
function _featureFlags() {
|
|
36
|
+
const data = require("@atlaspack/feature-flags");
|
|
37
|
+
_featureFlags = function () {
|
|
38
|
+
return data;
|
|
39
|
+
};
|
|
40
|
+
return data;
|
|
41
|
+
}
|
|
35
42
|
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
36
43
|
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
37
44
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
@@ -263,11 +270,20 @@ class BundleGraph {
|
|
|
263
270
|
}
|
|
264
271
|
for (let bundle of bundles) {
|
|
265
272
|
const conditions = bundleConditions.get(bundle.id) ?? new Map();
|
|
266
|
-
conditions.
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
273
|
+
const currentCondition = conditions.get(cond.key);
|
|
274
|
+
if ((0, _featureFlags().getFeatureFlag)('conditionalBundlingReporterSameConditionFix')) {
|
|
275
|
+
conditions.set(cond.key, {
|
|
276
|
+
bundle,
|
|
277
|
+
ifTrueBundles: [...((currentCondition === null || currentCondition === void 0 ? void 0 : currentCondition.ifTrueBundles) ?? []), ...ifTrueBundles],
|
|
278
|
+
ifFalseBundles: [...((currentCondition === null || currentCondition === void 0 ? void 0 : currentCondition.ifFalseBundles) ?? []), ...ifFalseBundles]
|
|
279
|
+
});
|
|
280
|
+
} else {
|
|
281
|
+
conditions.set(cond.key, {
|
|
282
|
+
bundle,
|
|
283
|
+
ifTrueBundles,
|
|
284
|
+
ifFalseBundles
|
|
285
|
+
});
|
|
286
|
+
}
|
|
271
287
|
bundleConditions.set(bundle.id, conditions);
|
|
272
288
|
}
|
|
273
289
|
}
|