perf(nav): reduce HTML output size ~34% by extracting repeated nav markup#3435
Conversation
Navigation HTML is embedded verbatim in every generated page, making
per-nav-item byte cost multiply across pages × nav items. At assembler
scale (69 repos, ~20k+ pages) this dominated the S3 upload volume.
Changes:
- Hoist hx-select-oob + preload from every nav anchor onto the two
parent <ul> elements (#nav-tree, dropdown <ul>); htmx 2.0 inherits
them, saving ~55 chars × nav item count per page
- Replace inline SVG chevron (336 chars) with <symbol>/<use> pattern;
symbol defined once in _GlobalLayout, each folder toggle drops to
~40 chars
- Extract repeated Tailwind utility strings into named CSS component
classes: .nav-link, .nav-folder-link, .nav-folder, .nav-toggle-btn,
.nav-chevron, .nav-badge, .nav-badge-{ns,cmd,alias}, .nav-subtree
- Remove inline badge style constants from template; move colours into
@layer components (immune to Tailwind purge, unlike arbitrary strings)
- Fix double-space bug in folder link class from empty isTopLevel branch
Measured on local isolated build (1,472 pages):
Before: 558 MB raw HTML → After: 370 MB (−33.8%, −128 KB/page)
Projected assembler impact: ~3–4 GB off the 11 GB S3 upload.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Warning Review limit reached
More reviews will be available in 12 minutes and 50 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Enterprise Run ID: 📒 Files selected for processing (4)
✨ Finishing Touches✨ Simplify code
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Why
The navigation tree HTML is embedded verbatim in every generated page. Because each nav item carries repeated inline strings (htmx attributes, long Tailwind utility chains, inline SVG, inline badge styles), the per-page cost multiplies across pages × nav items. At assembler scale — 69 repos, ~20k+ pages, each with its own nav tree — this was the dominant driver of the 11 GB S3 upload that takes ~6 minutes in CI.
What
htmx attribute hoisting —
hx-select-oobandpreloadwere emitted on every<a>in the nav tree. htmx 2.0 inherits these from the nearest ancestor, so moving them once onto<ul id="nav-tree">and the dropdown<ul>removes ~55 chars × nav-item-count per page.SVG symbol reuse — The 336-char inline chevron SVG was repeated for every expandable folder. It is now defined once as a
<symbol id="icon-chevron-down">in_GlobalLayout.cshtmland each folder references it with a 40-char<svg><use href="#icon-chevron-down"/></svg>.Named CSS component classes — Long repeated Tailwind utility strings are extracted into
@layer componentsinstyles.css:.nav-link,.nav-folder-link,.nav-folder,.nav-toggle-btn,.nav-chevron,.nav-badge,.nav-badge-{ns,cmd,alias},.nav-subtree. The inline badgestyle="background:…"strings (kept inline previously to avoid Tailwind purge) are moved into authored component classes, which are never purged.Double-space bug fix — Empty
@(isTopLevel ? "font-semibold" : "")expression was producing a double space in the folder link class attribute.How
The savings are proportional to nav tree size, not just page count — both multiply together. Measured on the local isolated build (1,472 pages, ~300 nav items):
Projected assembler impact: ~3–4 GB off the 11 GB S3 upload, bringing CI upload time from ~6 min toward ~4 min. Larger products (more nav items per tree) see proportionally bigger savings since every optimisation is per-nav-item.