Large refactors often can’t be split into stacked PRs, leaving a single pull request with thousands of files and hundreds of review comments. The GitHub Copilot app rebuilt its PR view to stay fast even on a 2,200-file diff with over a million changed lines and 400+ inline comments. The hard part isn’t virtualizing code rows—it’s that comment heights are unknowable until render time.
Why comments break the “all heights known” contract
A code-only diff is fast because every row is a line of code at a known height. You can compute the entire geometry table up front and never correct it. The Copilot app’s diff surface leans on that contract: an imperative recycled row renderer, typed-array offset math, and backend-owned diff documents streamed structure-first.
Comments destroy that assumption. A review thread’s height depends on markdown wrapping, expandable <details> blocks, reply composers, suggested changes, reactions, and async images. You can’t know it without rendering, and it keeps changing after first paint. Reserving a fixed-height slot with an estimator fails on big PRs: over-reserved comments leave gaps, under-reserved ones clip, and writing measured heights back into a shared offset table causes scroll jumps.
Two geometries instead of one
The fix is to stop forcing one geometry to serve both content types. The document’s total height becomes:
total height = deterministic code height (exact, known up front)
+ Σ dynamic block effective heights (estimated, then measured)
+ scroll padding
Code geometry stays exact and never rebuilds when a comment resizes. Dynamic blocks—review threads, drafts, composers—get their own index, keyed by identity (file, line, side) rather than pixel position. Each block keeps a fingerprint of height-affecting state and a width bucket, so a window resize doesn’t invalidate every measurement.
The measurement scheduler: one pass, not one observer per block
The first design used a ResizeObserver per block, but that creates a feedback loop: an observer writing heights back into the layout it’s watching can retrigger itself. What shipped instead is a single idle- and scroll-gated measurement pass:
- Runs when the visible range settles, never during an active scroll
- Scoped to blocks within ~2400px of the viewport, so work is O(viewport)
- Reads all mounted candidates in one batch—a single reflow with no writes in between
- Off-screen measurement is a bounded fallback: at most one render to correct a nearby block’s reservation
Mounted blocks keep a ResizeObserver, but by default it only flags the block for the idle pass. The exception is user-caused resizes (expanding a <details>, opening a composer, an image landing), which apply the correction in the same frame before paint. Two safeguards prevent the feedback loop: at most one synchronous commit per frame, and never during an active scroll.
Scroll anchoring: correct by identity, not by pixel
When a measured height differs from its estimate, the naive result is a viewport jump. The fix is to capture what the user is anchored to (a row or block, by identity), apply height deltas, resolve that anchor to its new pixel position, and scroll so it stays put. Rules keep it feeling right: adjust by delta for blocks above the viewport, don’t adjust for content hydrating below, and suppress above-block correction when the user toggles a visible block.
One sharp edge: the “don’t correct while scrolling” guard was initially fooled by programmatic scrolls. Toggling the file-tree sidebar changes the diff pane width, reflows wrapped lines, and emits a small scroll of its own. The guard read that as user interaction and skipped the correction, so the file drifted off screen. The fix was to distinguish user scrolls from surface-caused ones—any “is the user interacting?” check must be one your own side effects can’t satisfy.
The pipeline behind the surface
A fast diff surface is worthless if the data pipeline stalls. The Copilot app streams structure before content: the file tree and metadata paint while the document is still loading. This incremental request pattern is the same discipline we’ve seen in cache-aware model tiering, where you serve the cheap, structure-first layer immediately and defer the expensive content.
The supplied source text cuts off before detailing the full pipeline, but the principle is clear: a UI can only be as fast as the data feeding it, and streaming structure first keeps the surface responsive even on extreme PRs.
What this means for your own diff surfaces
If you’re building a virtualized list that mixes deterministic rows with dynamic content, the Copilot app’s approach offers a concrete pattern: split geometry into exact and estimated domains, measure lazily with a single scoped pass, and correct scroll position by identity. The alternative—one observer per dynamic block—will bite you at scale.
The tradeoff is complexity. You’re maintaining two geometry systems and a measurement scheduler with careful guards. But for PRs that can’t be split, that complexity is what keeps the review experience smooth.
Sources
AI-assisted summary compiled from the sources above, reviewed by a human before publishing.
