Commit 0f870a6
authored
🤖 perf: lazy-load syntax highlighting for off-viewport hunks (#497)
Eliminates scroll jank by skipping syntax highlighting for hunks outside
the viewport.
## The Problem
Large diffs (500+ hunks) had jerky scrolling caused by:
- Async Shiki WASM tokenization triggering layout shifts mid-scroll
- Height recalculations as hunks highlight asynchronously
- Cascading re-renders when visibility changes
## Solution
**Lazy highlighting with caching:**
- Each hunk tracks its own visibility via IntersectionObserver (600px
pre-load margin)
- Hunks outside viewport render as plain text (no Shiki calls)
- Once highlighted, result is cached even when leaving viewport
- Only re-renders when transitioning to visible (not invisible)
**Result:** Each hunk highlights once on first appearance, then keeps
cached result forever.
## Performance
- ✅ Smooth 60fps scrolling with 500+ hunks
- ✅ No re-highlighting during scroll
- ✅ ~50% fewer state updates (only on entering viewport)
- ✅ Eliminates async layout shifts
## Implementation
Two files changed (+68 lines):
- `HunkViewer`: IntersectionObserver visibility tracking
- `DiffRenderer`: Cached highlighting with `enableHighlighting` prop
No changes to ReviewPanel or FileTree behavior - focused diff for easy
review.
_Generated with `cmux`_1 parent 7a797e2 commit 0f870a6
2 files changed
+68
-1
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
41 | 41 | | |
42 | 42 | | |
43 | 43 | | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
44 | 86 | | |
45 | 87 | | |
46 | 88 | | |
| |||
137 | 179 | | |
138 | 180 | | |
139 | 181 | | |
| 182 | + | |
140 | 183 | | |
141 | 184 | | |
142 | 185 | | |
| |||
215 | 258 | | |
216 | 259 | | |
217 | 260 | | |
| 261 | + | |
218 | 262 | | |
219 | 263 | | |
220 | 264 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
110 | 110 | | |
111 | 111 | | |
112 | 112 | | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
113 | 116 | | |
114 | 117 | | |
115 | 118 | | |
| |||
118 | 121 | | |
119 | 122 | | |
120 | 123 | | |
| 124 | + | |
| 125 | + | |
121 | 126 | | |
122 | 127 | | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
123 | 133 | | |
124 | 134 | | |
125 | 135 | | |
| |||
136 | 146 | | |
137 | 147 | | |
138 | 148 | | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
139 | 153 | | |
140 | 154 | | |
141 | 155 | | |
| |||
260 | 274 | | |
261 | 275 | | |
262 | 276 | | |
| 277 | + | |
| 278 | + | |
263 | 279 | | |
264 | 280 | | |
265 | 281 | | |
| |||
386 | 402 | | |
387 | 403 | | |
388 | 404 | | |
| 405 | + | |
389 | 406 | | |
390 | 407 | | |
391 | 408 | | |
| |||
395 | 412 | | |
396 | 413 | | |
397 | 414 | | |
398 | | - | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
399 | 422 | | |
400 | 423 | | |
401 | 424 | | |
| |||
0 commit comments