@atlaspack/core 2.17.3 → 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 +26 -0
- package/lib/Atlaspack.js +3 -1
- package/lib/PackagerRunner.js +42 -8
- package/lib/RequestTracker.js +171 -84
- 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 +13 -13
- package/src/Atlaspack.js +5 -4
- package/src/PackagerRunner.js +60 -9
- package/src/RequestTracker.js +292 -134
- 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/src/RequestTracker.js
CHANGED
|
@@ -69,6 +69,7 @@ import type {
|
|
|
69
69
|
InternalGlob,
|
|
70
70
|
} from './types';
|
|
71
71
|
import {BuildAbortError, assertSignalNotAborted, hashFromOption} from './utils';
|
|
72
|
+
import {performance} from 'perf_hooks';
|
|
72
73
|
|
|
73
74
|
export const requestGraphEdgeTypes = {
|
|
74
75
|
subrequest: 2,
|
|
@@ -934,7 +935,10 @@ export class RequestGraph extends ContentGraph<
|
|
|
934
935
|
* True if this is the start-up (loading phase) invalidation.
|
|
935
936
|
*/
|
|
936
937
|
isInitialBuild: boolean = false,
|
|
937
|
-
):
|
|
938
|
+
): Promise<{|
|
|
939
|
+
didInvalidate: boolean,
|
|
940
|
+
invalidationsByPath: Map<string, number>,
|
|
941
|
+
|}> {
|
|
938
942
|
let didInvalidate = false;
|
|
939
943
|
let count = 0;
|
|
940
944
|
let predictedTime = 0;
|
|
@@ -972,7 +976,10 @@ export class RequestGraph extends ContentGraph<
|
|
|
972
976
|
return above;
|
|
973
977
|
};
|
|
974
978
|
|
|
979
|
+
const invalidationsByPath = new Map();
|
|
975
980
|
for (let {path: _path, type} of events) {
|
|
981
|
+
const invalidationsBefore = this.getInvalidNodeCount();
|
|
982
|
+
|
|
976
983
|
if (
|
|
977
984
|
!enableOptimization &&
|
|
978
985
|
process.env.ATLASPACK_DISABLE_CACHE_TIMEOUT !== 'true' &&
|
|
@@ -1018,7 +1025,10 @@ export class RequestGraph extends ContentGraph<
|
|
|
1018
1025
|
this.invalidNodeIds.add(id);
|
|
1019
1026
|
}
|
|
1020
1027
|
}
|
|
1021
|
-
return
|
|
1028
|
+
return {
|
|
1029
|
+
didInvalidate: true,
|
|
1030
|
+
invalidationsByPath: new Map(),
|
|
1031
|
+
};
|
|
1022
1032
|
}
|
|
1023
1033
|
|
|
1024
1034
|
// sometimes mac os reports update events as create events.
|
|
@@ -1131,6 +1141,13 @@ export class RequestGraph extends ContentGraph<
|
|
|
1131
1141
|
}
|
|
1132
1142
|
}
|
|
1133
1143
|
}
|
|
1144
|
+
|
|
1145
|
+
const invalidationsAfter = this.getInvalidNodeCount();
|
|
1146
|
+
const invalidationsForEvent = invalidationsAfter - invalidationsBefore;
|
|
1147
|
+
invalidationsByPath.set(
|
|
1148
|
+
_path,
|
|
1149
|
+
(invalidationsByPath.get(_path) ?? 0) + invalidationsForEvent,
|
|
1150
|
+
);
|
|
1134
1151
|
}
|
|
1135
1152
|
|
|
1136
1153
|
if (getFeatureFlag('fixQuadraticCacheInvalidation')) {
|
|
@@ -1151,7 +1168,10 @@ export class RequestGraph extends ContentGraph<
|
|
|
1151
1168
|
},
|
|
1152
1169
|
});
|
|
1153
1170
|
|
|
1154
|
-
return
|
|
1171
|
+
return {
|
|
1172
|
+
didInvalidate,
|
|
1173
|
+
invalidationsByPath,
|
|
1174
|
+
};
|
|
1155
1175
|
}
|
|
1156
1176
|
|
|
1157
1177
|
hasCachedRequestChunk(index: number): boolean {
|
|
@@ -1165,6 +1185,13 @@ export class RequestGraph extends ContentGraph<
|
|
|
1165
1185
|
removeCachedRequestChunkForNode(nodeId: number): void {
|
|
1166
1186
|
this.cachedRequestChunks.delete(Math.floor(nodeId / this.nodesPerBlob));
|
|
1167
1187
|
}
|
|
1188
|
+
|
|
1189
|
+
/**
|
|
1190
|
+
* Returns the number of invalidated nodes in the graph.
|
|
1191
|
+
*/
|
|
1192
|
+
getInvalidNodeCount(): number {
|
|
1193
|
+
return this.invalidNodeIds.size;
|
|
1194
|
+
}
|
|
1168
1195
|
}
|
|
1169
1196
|
|
|
1170
1197
|
export default class RequestTracker {
|
|
@@ -1288,7 +1315,13 @@ export default class RequestTracker {
|
|
|
1288
1315
|
}
|
|
1289
1316
|
}
|
|
1290
1317
|
|
|
1291
|
-
respondToFSEvents(
|
|
1318
|
+
respondToFSEvents(
|
|
1319
|
+
events: Array<Event>,
|
|
1320
|
+
threshold: number,
|
|
1321
|
+
): Promise<{|
|
|
1322
|
+
didInvalidate: boolean,
|
|
1323
|
+
invalidationsByPath: Map<string, number>,
|
|
1324
|
+
|}> {
|
|
1292
1325
|
return this.graph.respondToFSEvents(events, this.options, threshold);
|
|
1293
1326
|
}
|
|
1294
1327
|
|
|
@@ -1499,130 +1532,139 @@ export default class RequestTracker {
|
|
|
1499
1532
|
}
|
|
1500
1533
|
}
|
|
1501
1534
|
|
|
1502
|
-
await runCacheImprovements(
|
|
1503
|
-
async (cache) => {
|
|
1504
|
-
await cache.getNativeRef().startWriteTransaction();
|
|
1505
|
-
},
|
|
1506
|
-
() => Promise.resolve(),
|
|
1507
|
-
);
|
|
1508
|
-
|
|
1509
1535
|
let cacheKey = getCacheKey(this.options);
|
|
1510
|
-
let requestGraphKey =
|
|
1511
|
-
|
|
1536
|
+
let requestGraphKey = getFeatureFlag('cachePerformanceImprovements')
|
|
1537
|
+
? `${cacheKey}/RequestGraph`
|
|
1538
|
+
: `requestGraph-${cacheKey}`;
|
|
1539
|
+
let snapshotKey = getFeatureFlag('cachePerformanceImprovements')
|
|
1540
|
+
? `${cacheKey}/snapshot`
|
|
1541
|
+
: `snapshot-${cacheKey}`;
|
|
1512
1542
|
|
|
1513
1543
|
if (this.options.shouldDisableCache) {
|
|
1514
1544
|
return;
|
|
1515
1545
|
}
|
|
1516
1546
|
|
|
1517
1547
|
let total = 0;
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1548
|
+
await runCacheImprovements(
|
|
1549
|
+
async (cache) => {
|
|
1550
|
+
await cache.getNativeRef().startWriteTransaction();
|
|
1551
|
+
},
|
|
1552
|
+
() => Promise.resolve(),
|
|
1553
|
+
);
|
|
1554
|
+
try {
|
|
1555
|
+
report({
|
|
1556
|
+
type: 'cache',
|
|
1557
|
+
phase: 'start',
|
|
1558
|
+
total,
|
|
1559
|
+
size: this.graph.nodes.length,
|
|
1560
|
+
});
|
|
1524
1561
|
|
|
1525
|
-
|
|
1562
|
+
let serialisedGraph = this.graph.serialize();
|
|
1526
1563
|
|
|
1527
|
-
|
|
1528
|
-
|
|
1564
|
+
// Delete an existing request graph cache, to prevent invalid states
|
|
1565
|
+
await this.options.cache.deleteLargeBlob(requestGraphKey);
|
|
1529
1566
|
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1567
|
+
const serialiseAndSet = async (
|
|
1568
|
+
key: string,
|
|
1569
|
+
// $FlowFixMe serialise input is any type
|
|
1570
|
+
contents: any,
|
|
1571
|
+
): Promise<void> => {
|
|
1572
|
+
if (signal?.aborted) {
|
|
1573
|
+
throw new Error('Serialization was aborted');
|
|
1574
|
+
}
|
|
1538
1575
|
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1576
|
+
await runCacheImprovements(
|
|
1577
|
+
(cache) => {
|
|
1578
|
+
instrument(
|
|
1579
|
+
`RequestTracker::writeToCache::cache.put(${key})`,
|
|
1580
|
+
() => {
|
|
1581
|
+
cache.getNativeRef().putNoConfirm(key, serialize(contents));
|
|
1582
|
+
},
|
|
1583
|
+
);
|
|
1584
|
+
return Promise.resolve();
|
|
1585
|
+
},
|
|
1586
|
+
async () => {
|
|
1587
|
+
await this.options.cache.setLargeBlob(
|
|
1588
|
+
key,
|
|
1589
|
+
serialize(contents),
|
|
1590
|
+
signal
|
|
1591
|
+
? {
|
|
1592
|
+
signal: signal,
|
|
1593
|
+
}
|
|
1594
|
+
: undefined,
|
|
1595
|
+
);
|
|
1596
|
+
},
|
|
1597
|
+
);
|
|
1558
1598
|
|
|
1559
|
-
|
|
1599
|
+
total += 1;
|
|
1560
1600
|
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1601
|
+
report({
|
|
1602
|
+
type: 'cache',
|
|
1603
|
+
phase: 'write',
|
|
1604
|
+
total,
|
|
1605
|
+
size: this.graph.nodes.length,
|
|
1606
|
+
});
|
|
1607
|
+
};
|
|
1568
1608
|
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1609
|
+
let queue = new PromiseQueue({
|
|
1610
|
+
maxConcurrent: 32,
|
|
1611
|
+
});
|
|
1572
1612
|
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1613
|
+
// Preallocating a sparse array is faster than pushing when N is high enough
|
|
1614
|
+
let cacheableNodes = new Array(serialisedGraph.nodes.length);
|
|
1615
|
+
for (let i = 0; i < serialisedGraph.nodes.length; i += 1) {
|
|
1616
|
+
let node = serialisedGraph.nodes[i];
|
|
1577
1617
|
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1618
|
+
let resultCacheKey = node?.resultCacheKey;
|
|
1619
|
+
if (
|
|
1620
|
+
node?.type === REQUEST &&
|
|
1621
|
+
resultCacheKey != null &&
|
|
1622
|
+
node?.result != null
|
|
1623
|
+
) {
|
|
1624
|
+
queue.add(() => serialiseAndSet(resultCacheKey, node.result));
|
|
1585
1625
|
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1626
|
+
// eslint-disable-next-line no-unused-vars
|
|
1627
|
+
let {result: _, ...newNode} = node;
|
|
1628
|
+
cacheableNodes[i] = newNode;
|
|
1629
|
+
} else {
|
|
1630
|
+
cacheableNodes[i] = node;
|
|
1631
|
+
}
|
|
1591
1632
|
}
|
|
1592
|
-
}
|
|
1593
1633
|
|
|
1594
|
-
|
|
1634
|
+
let nodeCountsPerBlob = [];
|
|
1595
1635
|
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1636
|
+
for (
|
|
1637
|
+
let i = 0;
|
|
1638
|
+
i * this.graph.nodesPerBlob < cacheableNodes.length;
|
|
1639
|
+
i += 1
|
|
1640
|
+
) {
|
|
1641
|
+
let nodesStartIndex = i * this.graph.nodesPerBlob;
|
|
1642
|
+
let nodesEndIndex = Math.min(
|
|
1643
|
+
(i + 1) * this.graph.nodesPerBlob,
|
|
1644
|
+
cacheableNodes.length,
|
|
1645
|
+
);
|
|
1606
1646
|
|
|
1607
|
-
|
|
1647
|
+
nodeCountsPerBlob.push(nodesEndIndex - nodesStartIndex);
|
|
1608
1648
|
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1649
|
+
if (!this.graph.hasCachedRequestChunk(i)) {
|
|
1650
|
+
// We assume the request graph nodes are immutable and won't change
|
|
1651
|
+
let nodesToCache = cacheableNodes.slice(
|
|
1652
|
+
nodesStartIndex,
|
|
1653
|
+
nodesEndIndex,
|
|
1654
|
+
);
|
|
1612
1655
|
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1656
|
+
queue.add(() =>
|
|
1657
|
+
serialiseAndSet(
|
|
1658
|
+
getRequestGraphNodeKey(i, cacheKey),
|
|
1659
|
+
nodesToCache,
|
|
1660
|
+
).then(() => {
|
|
1661
|
+
// Succeeded in writing to disk, save that we have completed this chunk
|
|
1662
|
+
this.graph.setCachedRequestChunk(i);
|
|
1663
|
+
}),
|
|
1664
|
+
);
|
|
1665
|
+
}
|
|
1622
1666
|
}
|
|
1623
|
-
}
|
|
1624
1667
|
|
|
1625
|
-
try {
|
|
1626
1668
|
await queue.run();
|
|
1627
1669
|
|
|
1628
1670
|
// Set the request graph after the queue is flushed to avoid writing an invalid state
|
|
@@ -1634,7 +1676,7 @@ export default class RequestTracker {
|
|
|
1634
1676
|
|
|
1635
1677
|
await runCacheImprovements(
|
|
1636
1678
|
() =>
|
|
1637
|
-
serialiseAndSet(
|
|
1679
|
+
serialiseAndSet(`${cacheKey}/cache_metadata`, {
|
|
1638
1680
|
version: ATLASPACK_VERSION,
|
|
1639
1681
|
entries: this.options.entries,
|
|
1640
1682
|
mode: this.options.mode,
|
|
@@ -1655,15 +1697,15 @@ export default class RequestTracker {
|
|
|
1655
1697
|
} catch (err) {
|
|
1656
1698
|
// If we have aborted, ignore the error and continue
|
|
1657
1699
|
if (!signal?.aborted) throw err;
|
|
1700
|
+
} finally {
|
|
1701
|
+
await runCacheImprovements(
|
|
1702
|
+
async (cache) => {
|
|
1703
|
+
await cache.getNativeRef().commitWriteTransaction();
|
|
1704
|
+
},
|
|
1705
|
+
() => Promise.resolve(),
|
|
1706
|
+
);
|
|
1658
1707
|
}
|
|
1659
1708
|
|
|
1660
|
-
await runCacheImprovements(
|
|
1661
|
-
async (cache) => {
|
|
1662
|
-
await cache.getNativeRef().commitWriteTransaction();
|
|
1663
|
-
},
|
|
1664
|
-
() => Promise.resolve(),
|
|
1665
|
-
);
|
|
1666
|
-
|
|
1667
1709
|
report({type: 'cache', phase: 'end', total, size: this.graph.nodes.length});
|
|
1668
1710
|
}
|
|
1669
1711
|
|
|
@@ -1695,6 +1737,18 @@ export function getWatcherOptions({
|
|
|
1695
1737
|
}
|
|
1696
1738
|
|
|
1697
1739
|
function getCacheKey(options) {
|
|
1740
|
+
if (getFeatureFlag('cachePerformanceImprovements')) {
|
|
1741
|
+
const hash = hashString(
|
|
1742
|
+
`${ATLASPACK_VERSION}:${JSON.stringify(options.entries)}:${
|
|
1743
|
+
options.mode
|
|
1744
|
+
}:${options.shouldBuildLazily ? 'lazy' : 'eager'}:${
|
|
1745
|
+
options.watchBackend ?? ''
|
|
1746
|
+
}`,
|
|
1747
|
+
);
|
|
1748
|
+
|
|
1749
|
+
return `RequestTracker/${ATLASPACK_VERSION}/${hash}`;
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1698
1752
|
return hashString(
|
|
1699
1753
|
`${ATLASPACK_VERSION}:${JSON.stringify(options.entries)}:${options.mode}:${
|
|
1700
1754
|
options.shouldBuildLazily ? 'lazy' : 'eager'
|
|
@@ -1703,6 +1757,10 @@ function getCacheKey(options) {
|
|
|
1703
1757
|
}
|
|
1704
1758
|
|
|
1705
1759
|
function getRequestGraphNodeKey(index: number, cacheKey: string) {
|
|
1760
|
+
if (getFeatureFlag('cachePerformanceImprovements')) {
|
|
1761
|
+
return `${cacheKey}/RequestGraph/nodes/${index}`;
|
|
1762
|
+
}
|
|
1763
|
+
|
|
1706
1764
|
return `requestGraph-nodes-${index}-${cacheKey}`;
|
|
1707
1765
|
}
|
|
1708
1766
|
|
|
@@ -1714,9 +1772,15 @@ export async function readAndDeserializeRequestGraph(
|
|
|
1714
1772
|
let bufferLength = 0;
|
|
1715
1773
|
|
|
1716
1774
|
const getAndDeserialize = async (key: string) => {
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1775
|
+
if (getFeatureFlag('cachePerformanceImprovements')) {
|
|
1776
|
+
const buffer = await cache.getBlob(key);
|
|
1777
|
+
bufferLength += Buffer.byteLength(buffer);
|
|
1778
|
+
return deserialize(buffer);
|
|
1779
|
+
} else {
|
|
1780
|
+
const buffer = await cache.getLargeBlob(key);
|
|
1781
|
+
bufferLength += Buffer.byteLength(buffer);
|
|
1782
|
+
return deserialize(buffer);
|
|
1783
|
+
}
|
|
1720
1784
|
};
|
|
1721
1785
|
|
|
1722
1786
|
let serializedRequestGraph = await getAndDeserialize(requestGraphKey);
|
|
@@ -1749,9 +1813,14 @@ async function loadRequestGraph(options): Async<RequestGraph> {
|
|
|
1749
1813
|
}
|
|
1750
1814
|
|
|
1751
1815
|
let cacheKey = getCacheKey(options);
|
|
1752
|
-
let requestGraphKey =
|
|
1816
|
+
let requestGraphKey = getFeatureFlag('cachePerformanceImprovements')
|
|
1817
|
+
? `${cacheKey}/RequestGraph`
|
|
1818
|
+
: `requestGraph-${cacheKey}`;
|
|
1819
|
+
|
|
1753
1820
|
let timeout;
|
|
1754
|
-
const snapshotKey =
|
|
1821
|
+
const snapshotKey = getFeatureFlag('cachePerformanceImprovements')
|
|
1822
|
+
? `${cacheKey}/snapshot`
|
|
1823
|
+
: `snapshot-${cacheKey}`;
|
|
1755
1824
|
const snapshotPath = path.join(options.cacheDir, snapshotKey + '.txt');
|
|
1756
1825
|
|
|
1757
1826
|
const commonMeta = {
|
|
@@ -1774,7 +1843,11 @@ async function loadRequestGraph(options): Async<RequestGraph> {
|
|
|
1774
1843
|
},
|
|
1775
1844
|
});
|
|
1776
1845
|
|
|
1777
|
-
|
|
1846
|
+
const hasRequestGraphInCache = getFeatureFlag('cachePerformanceImprovements')
|
|
1847
|
+
? await options.cache.has(requestGraphKey)
|
|
1848
|
+
: await options.cache.hasLargeBlob(requestGraphKey);
|
|
1849
|
+
|
|
1850
|
+
if (hasRequestGraphInCache) {
|
|
1778
1851
|
try {
|
|
1779
1852
|
let {requestGraph} = await readAndDeserializeRequestGraph(
|
|
1780
1853
|
options.cache,
|
|
@@ -1863,7 +1936,11 @@ async function loadRequestGraph(options): Async<RequestGraph> {
|
|
|
1863
1936
|
*/
|
|
1864
1937
|
type InvalidationFn = {|
|
|
1865
1938
|
key: string,
|
|
1866
|
-
fn: () =>
|
|
1939
|
+
fn: () =>
|
|
1940
|
+
| InvalidationDetail
|
|
1941
|
+
| Promise<InvalidationDetail>
|
|
1942
|
+
| void
|
|
1943
|
+
| Promise<void>,
|
|
1867
1944
|
|};
|
|
1868
1945
|
|
|
1869
1946
|
type InvalidationStats = {|
|
|
@@ -1893,6 +1970,33 @@ type InvalidationStats = {|
|
|
|
1893
1970
|
invalidations: InvalidationFnStats[],
|
|
1894
1971
|
|};
|
|
1895
1972
|
|
|
1973
|
+
/**
|
|
1974
|
+
* Details about an invalidation.
|
|
1975
|
+
*
|
|
1976
|
+
* If this is a fs events invalidation, this key will contain statistics about invalidations
|
|
1977
|
+
* by path.
|
|
1978
|
+
*
|
|
1979
|
+
* If this is a env or option invalidation, this key will contain the list of changed environment
|
|
1980
|
+
* variables or options.
|
|
1981
|
+
*/
|
|
1982
|
+
type InvalidationDetail = string[] | FSInvalidationStats;
|
|
1983
|
+
|
|
1984
|
+
/**
|
|
1985
|
+
* Number of invalidations for a given file-system event.
|
|
1986
|
+
*/
|
|
1987
|
+
type FSInvalidation = {|
|
|
1988
|
+
path: string,
|
|
1989
|
+
count: number,
|
|
1990
|
+
|};
|
|
1991
|
+
|
|
1992
|
+
type FSInvalidationStats = {|
|
|
1993
|
+
/**
|
|
1994
|
+
* This list will be sorted by the number of nodes invalidated and only the top 10 will be
|
|
1995
|
+
* included.
|
|
1996
|
+
*/
|
|
1997
|
+
biggestInvalidations: FSInvalidation[],
|
|
1998
|
+
|};
|
|
1999
|
+
|
|
1896
2000
|
/**
|
|
1897
2001
|
* Information about a certain cache invalidation type.
|
|
1898
2002
|
*/
|
|
@@ -1913,8 +2017,14 @@ type InvalidationFnStats = {|
|
|
|
1913
2017
|
count: number,
|
|
1914
2018
|
/**
|
|
1915
2019
|
* If this is a env or option invalidation, this key will contain the list of changed values.
|
|
2020
|
+
*
|
|
2021
|
+
* If this is a fs events invalidation, this key will contain statistics about invalidations
|
|
1916
2022
|
*/
|
|
1917
|
-
|
|
2023
|
+
detail: null | InvalidationDetail,
|
|
2024
|
+
/**
|
|
2025
|
+
* Time in milliseconds it took to run the invalidation.
|
|
2026
|
+
*/
|
|
2027
|
+
duration: number,
|
|
1918
2028
|
|};
|
|
1919
2029
|
|
|
1920
2030
|
/**
|
|
@@ -1923,7 +2033,7 @@ type InvalidationFnStats = {|
|
|
|
1923
2033
|
*
|
|
1924
2034
|
* Returns the count of nodes invalidated by each invalidation type.
|
|
1925
2035
|
*/
|
|
1926
|
-
async function invalidateRequestGraph(
|
|
2036
|
+
export async function invalidateRequestGraph(
|
|
1927
2037
|
requestGraph: RequestGraph,
|
|
1928
2038
|
options: AtlaspackOptions,
|
|
1929
2039
|
events: Event[],
|
|
@@ -1947,14 +2057,7 @@ async function invalidateRequestGraph(
|
|
|
1947
2057
|
},
|
|
1948
2058
|
{
|
|
1949
2059
|
key: 'fsEvents',
|
|
1950
|
-
fn:
|
|
1951
|
-
await requestGraph.respondToFSEvents(
|
|
1952
|
-
options.unstableFileInvalidations || events,
|
|
1953
|
-
options,
|
|
1954
|
-
10000,
|
|
1955
|
-
true,
|
|
1956
|
-
);
|
|
1957
|
-
},
|
|
2060
|
+
fn: () => invalidateRequestGraphFSEvents(requestGraph, options, events),
|
|
1958
2061
|
},
|
|
1959
2062
|
];
|
|
1960
2063
|
|
|
@@ -1984,22 +2087,61 @@ async function invalidateRequestGraph(
|
|
|
1984
2087
|
};
|
|
1985
2088
|
}
|
|
1986
2089
|
|
|
2090
|
+
interface InvalidateRequestGraphFSEventsInput {
|
|
2091
|
+
respondToFSEvents(
|
|
2092
|
+
events: Event[],
|
|
2093
|
+
options: AtlaspackOptions,
|
|
2094
|
+
timeout: number,
|
|
2095
|
+
shouldLog: boolean,
|
|
2096
|
+
): Promise<{invalidationsByPath: Map<string, number>, ...}>;
|
|
2097
|
+
}
|
|
2098
|
+
|
|
2099
|
+
/**
|
|
2100
|
+
* Invalidate the request graph based on file-system events.
|
|
2101
|
+
*
|
|
2102
|
+
* Returns statistics about the invalidations.
|
|
2103
|
+
*/
|
|
2104
|
+
export async function invalidateRequestGraphFSEvents(
|
|
2105
|
+
requestGraph: InvalidateRequestGraphFSEventsInput,
|
|
2106
|
+
options: AtlaspackOptions,
|
|
2107
|
+
events: Event[],
|
|
2108
|
+
): Promise<FSInvalidationStats> {
|
|
2109
|
+
const {invalidationsByPath} = await requestGraph.respondToFSEvents(
|
|
2110
|
+
options.unstableFileInvalidations || events,
|
|
2111
|
+
options,
|
|
2112
|
+
10000,
|
|
2113
|
+
true,
|
|
2114
|
+
);
|
|
2115
|
+
const biggestInvalidations =
|
|
2116
|
+
getBiggestFSEventsInvalidations(invalidationsByPath);
|
|
2117
|
+
|
|
2118
|
+
return {
|
|
2119
|
+
biggestInvalidations,
|
|
2120
|
+
};
|
|
2121
|
+
}
|
|
2122
|
+
|
|
2123
|
+
interface RunInvalidationInput {
|
|
2124
|
+
getInvalidNodeCount(): number;
|
|
2125
|
+
}
|
|
2126
|
+
|
|
1987
2127
|
/**
|
|
1988
2128
|
* Runs an invalidation function and reports metrics.
|
|
1989
2129
|
*/
|
|
1990
|
-
async function runInvalidation(
|
|
1991
|
-
requestGraph:
|
|
2130
|
+
export async function runInvalidation(
|
|
2131
|
+
requestGraph: RunInvalidationInput,
|
|
1992
2132
|
invalidationFn: InvalidationFn,
|
|
1993
2133
|
): Promise<InvalidationFnStats> {
|
|
1994
|
-
const
|
|
2134
|
+
const start = performance.now();
|
|
2135
|
+
const startInvalidationCount = requestGraph.getInvalidNodeCount();
|
|
1995
2136
|
const result = await invalidationFn.fn();
|
|
1996
|
-
const count = requestGraph.
|
|
2137
|
+
const count = requestGraph.getInvalidNodeCount() - startInvalidationCount;
|
|
2138
|
+
const duration = performance.now() - start;
|
|
1997
2139
|
|
|
1998
2140
|
return {
|
|
1999
2141
|
key: invalidationFn.key,
|
|
2000
2142
|
count,
|
|
2001
|
-
|
|
2002
|
-
|
|
2143
|
+
detail: result ?? null,
|
|
2144
|
+
duration,
|
|
2003
2145
|
};
|
|
2004
2146
|
}
|
|
2005
2147
|
|
|
@@ -2054,3 +2196,19 @@ export function cleanUpOrphans<N, E: number>(graph: Graph<N, E>): NodeId[] {
|
|
|
2054
2196
|
|
|
2055
2197
|
return removedNodeIds;
|
|
2056
2198
|
}
|
|
2199
|
+
|
|
2200
|
+
/**
|
|
2201
|
+
* Returns paths that invalidated the most nodes
|
|
2202
|
+
*/
|
|
2203
|
+
export function getBiggestFSEventsInvalidations(
|
|
2204
|
+
invalidationsByPath: Map<string, number>,
|
|
2205
|
+
limit: number = 10,
|
|
2206
|
+
): Array<FSInvalidation> {
|
|
2207
|
+
const invalidations = [];
|
|
2208
|
+
for (const [path, count] of invalidationsByPath) {
|
|
2209
|
+
invalidations.push({path, count});
|
|
2210
|
+
}
|
|
2211
|
+
invalidations.sort((a, b) => b.count - a.count);
|
|
2212
|
+
|
|
2213
|
+
return invalidations.slice(0, limit);
|
|
2214
|
+
}
|
package/src/UncommittedAsset.js
CHANGED
|
@@ -30,7 +30,12 @@ import {ATLASPACK_VERSION} from './constants';
|
|
|
30
30
|
import {createAsset, createAssetIdFromOptions} from './assetUtils';
|
|
31
31
|
import {BundleBehaviorNames} from './types';
|
|
32
32
|
import {invalidateOnFileCreateToInternal, createInvalidations} from './utils';
|
|
33
|
-
import {
|
|
33
|
+
import {
|
|
34
|
+
type ProjectPath,
|
|
35
|
+
fromProjectPath,
|
|
36
|
+
fromProjectPathRelative,
|
|
37
|
+
} from './projectPath';
|
|
38
|
+
import {getFeatureFlag} from '@atlaspack/feature-flags';
|
|
34
39
|
|
|
35
40
|
type UncommittedAssetOptions = {|
|
|
36
41
|
value: Asset,
|
|
@@ -153,7 +158,9 @@ export default class UncommittedAsset {
|
|
|
153
158
|
size = content.length;
|
|
154
159
|
}
|
|
155
160
|
|
|
161
|
+
// Maybe we should just store this in a file instead of LMDB
|
|
156
162
|
await this.options.cache.setBlob(contentKey, content);
|
|
163
|
+
|
|
157
164
|
return {size, hash};
|
|
158
165
|
}
|
|
159
166
|
|
|
@@ -214,6 +221,9 @@ export default class UncommittedAsset {
|
|
|
214
221
|
this.clearAST();
|
|
215
222
|
}
|
|
216
223
|
|
|
224
|
+
/**
|
|
225
|
+
* @deprecated This has been broken on any cache other than FSCache for a long time.
|
|
226
|
+
*/
|
|
217
227
|
setStream(stream: Readable) {
|
|
218
228
|
this.content = stream;
|
|
219
229
|
this.clearAST();
|
|
@@ -296,6 +306,11 @@ export default class UncommittedAsset {
|
|
|
296
306
|
}
|
|
297
307
|
|
|
298
308
|
getCacheKey(key: string): string {
|
|
309
|
+
if (getFeatureFlag('cachePerformanceImprovements')) {
|
|
310
|
+
const filePath = fromProjectPathRelative(this.value.filePath);
|
|
311
|
+
return `Asset/${ATLASPACK_VERSION}/${filePath}/${this.value.id}/${key}`;
|
|
312
|
+
}
|
|
313
|
+
|
|
299
314
|
return hashString(ATLASPACK_VERSION + key + this.value.id);
|
|
300
315
|
}
|
|
301
316
|
|
|
@@ -100,11 +100,15 @@ export class PluginConfig implements IPluginConfig {
|
|
|
100
100
|
// eslint-disable-next-line no-unused-vars
|
|
101
101
|
filePaths: Array<FilePath>,
|
|
102
102
|
// eslint-disable-next-line no-unused-vars
|
|
103
|
-
options?:
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
103
|
+
options?:
|
|
104
|
+
| {|
|
|
105
|
+
packageKey?: string,
|
|
106
|
+
parse?: boolean,
|
|
107
|
+
exclude?: boolean,
|
|
108
|
+
|}
|
|
109
|
+
| {|
|
|
110
|
+
configKey?: string,
|
|
111
|
+
|},
|
|
108
112
|
): Promise<?ConfigResultWithFilePath<T>> {
|
|
109
113
|
return this.#inner.getConfigFrom(searchPath, filePaths, options);
|
|
110
114
|
}
|