@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.
@@ -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
- if (env[keyFromEnvContentKey(node.id)] !== node.value) {
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
- if ((0, _utils2.hashFromOption)(options[keyFromOptionContentKey(node.id)]) !== node.hash) {
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 true;
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 didInvalidate && this.invalidNodeIds.size > 0;
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
- (0, _ReporterRunner.report)({
957
- type: 'cache',
958
- phase: 'start',
959
- total,
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: 'write',
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
- // Preallocating a sparse array is faster than pushing when N is high enough
993
- let cacheableNodes = new Array(serialisedGraph.nodes.length);
994
- for (let i = 0; i < serialisedGraph.nodes.length; i += 1) {
995
- let node = serialisedGraph.nodes[i];
996
- let resultCacheKey = node === null || node === void 0 ? void 0 : node.resultCacheKey;
997
- if ((node === null || node === void 0 ? void 0 : node.type) === REQUEST && resultCacheKey != null && (node === null || node === void 0 ? void 0 : node.result) != null) {
998
- queue.add(() => serialiseAndSet(resultCacheKey, node.result));
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
- // eslint-disable-next-line no-unused-vars
1001
- let {
1002
- result: _,
1003
- ...newNode
1004
- } = node;
1005
- cacheableNodes[i] = newNode;
1006
- } else {
1007
- cacheableNodes[i] = node;
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
- let nodeCountsPerBlob = [];
1011
- for (let i = 0; i * this.graph.nodesPerBlob < cacheableNodes.length; i += 1) {
1012
- let nodesStartIndex = i * this.graph.nodesPerBlob;
1013
- let nodesEndIndex = Math.min((i + 1) * this.graph.nodesPerBlob, cacheableNodes.length);
1014
- nodeCountsPerBlob.push(nodesEndIndex - nodesStartIndex);
1015
- if (!this.graph.hasCachedRequestChunk(i)) {
1016
- // We assume the request graph nodes are immutable and won't change
1017
- let nodesToCache = cacheableNodes.slice(nodesStartIndex, nodesEndIndex);
1018
- queue.add(() => serialiseAndSet(getRequestGraphNodeKey(i, cacheKey), nodesToCache).then(() => {
1019
- // Succeeded in writing to disk, save that we have completed this chunk
1020
- this.graph.setCachedRequestChunk(i);
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(`request_tracker:cache_metadata:${cacheKey}`, {
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, `snapshot-${cacheKey}` + '.txt');
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
- let buffer = await cache.getLargeBlob(key);
1095
- bufferLength += Buffer.byteLength(buffer);
1096
- return (0, _buildCache().deserialize)(buffer);
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
- cacheKey,
1127
- snapshotKey
1206
+ ...commonMeta
1128
1207
  }
1129
1208
  });
1130
- if (await options.cache.hasLargeBlob(requestGraphKey)) {
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
- requestGraph.invalidateUnpredictableNodes();
1155
- requestGraph.invalidateOnBuildNodes();
1156
- requestGraph.invalidateEnvNodes(options.env);
1157
- requestGraph.invalidateOptionNodes(options);
1158
- await requestGraph.respondToFSEvents(options.unstableFileInvalidations || events, options, 10000, true);
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
- cacheKey,
1174
- snapshotKey
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
  }
@@ -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) {
@@ -149,6 +149,14 @@ class AtlaspackWorker {
149
149
  }
150
150
  };
151
151
  }
152
+ if (result.isExcluded) {
153
+ return {
154
+ invalidations: [],
155
+ resolution: {
156
+ type: 'excluded'
157
+ }
158
+ };
159
+ }
152
160
  return {
153
161
  invalidations: [],
154
162
  resolution: {
@@ -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.set(cond.key, {
267
- bundle,
268
- ifTrueBundles,
269
- ifFalseBundles
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
  }