diff --git a/packages/trace-viewer/src/snapshotRenderer.ts b/packages/trace-viewer/src/snapshotRenderer.ts index 0b458c0cb5..11e63de04f 100644 --- a/packages/trace-viewer/src/snapshotRenderer.ts +++ b/packages/trace-viewer/src/snapshotRenderer.ts @@ -25,6 +25,34 @@ function isSubtreeReferenceSnapshot(n: NodeSnapshot): n is SubtreeReferenceSnaps return Array.isArray(n) && Array.isArray(n[0]); } +let cacheSize = 0; +const cache = new Map(); +const CACHE_SIZE = 300_000_000; // 300mb + +function lruCache(key: SnapshotRenderer, compute: () => string): string { + if (cache.has(key)) { + const value = cache.get(key)!; + // reinserting makes this the least recently used entry + cache.delete(key); + cache.set(key, value); + return value; + } + + + const result = compute(); + + while (cache.size && cacheSize + result.length > CACHE_SIZE) { + const [firstKey, firstValue] = cache.entries().next().value; + cacheSize -= firstValue.length; + cache.delete(firstKey); + } + + cache.set(key, result); + cacheSize += result.length; + + return result; +} + export class SnapshotRenderer { private _snapshots: FrameSnapshot[]; private _index: number; @@ -51,89 +79,89 @@ export class SnapshotRenderer { } render(): RenderedFrameSnapshot { - const visit = (n: NodeSnapshot, snapshotIndex: number, parentTag: string | undefined, parentAttrs: [string, string][] | undefined): string => { + const result: string[] = []; + const visit = (n: NodeSnapshot, snapshotIndex: number, parentTag: string | undefined, parentAttrs: [string, string][] | undefined) => { // Text node. if (typeof n === 'string') { // Best-effort Electron support: rewrite custom protocol in url() links in stylesheets. // Old snapshotter was sending lower-case. if (parentTag === 'STYLE' || parentTag === 'style') - return rewriteURLsInStyleSheetForCustomProtocol(n); - return escapeHTML(n); + result.push(rewriteURLsInStyleSheetForCustomProtocol(n)); + else + result.push(escapeHTML(n)); + return; } - if (!(n as any)._string) { - if (isSubtreeReferenceSnapshot(n)) { - // Node reference. - const referenceIndex = snapshotIndex - n[0][0]; - if (referenceIndex >= 0 && referenceIndex <= snapshotIndex) { - const nodes = snapshotNodes(this._snapshots[referenceIndex]); - const nodeIndex = n[0][1]; - if (nodeIndex >= 0 && nodeIndex < nodes.length) - (n as any)._string = visit(nodes[nodeIndex], referenceIndex, parentTag, parentAttrs); - } - } else if (isNodeNameAttributesChildNodesSnapshot(n)) { - const [name, nodeAttrs, ...children] = n; - // Element node. - // Note that