Repository navigation
Public sites perf · Docs: load like a static site #140
Description
Part of the docs site performance plan (parent issue linked above). Readers expect docs to load like a static site. #71 (page weight) and #72 (caching, docs included) cover the general work; this issue covers the docs-specific gaps they leave. OpenAPI operation pages (#26, docs/openapi-support.md) inherit everything here.
Goal
Docs pages are served from cache on every view, including the first view after a publish, and the cost of a docs page doesn't grow with the size of the docs.
Tasks
-
Read only the requested page.
getDocumentationSnapshotreturns the full TipTap content of every published doc, andgetDocumentationBySlugpicks one page out of it (apps/sites/lib/api.ts:272,apps/api/src/public/routes.tsgetDocumentationSnapshot). Split it into:- a navigation read (titles, slugs, sections, order, excerpts), used by the sidebar, feed and collection pages;
- a per-page content read.
Both are cached under
docs:<team>(Public sites perf · Phase 2: built-in caching layer (cache components + shared Redis handler, docs cacheable) #72), and both come from one publication, so one response stays consistent (docs-management.md§23.3). -
Warm the cache after a publish. Activation clears
docs:<team>, so the first reader of each page waits for a render. After the sites docs webhook clears the tag, re-render the published docs routes (from the navigation read) in the background with bounded concurrency. The aim is static-site behaviour: the first reader after a publish gets a cached page. -
Prefetch docs links on hover only. Sidebar, feed and collection links in
apps/sites/components/themed-docs.tsxuse the default Next.jsLink, which prefetches every link in the viewport in production. A large sidebar fires dozens of RSC requests per page view. -
Docs images. Check that images in the docs body (
TextRenderer) go through Public sites perf · Phase 1: page weight (server-rendered blocks, lazy chat, images, fonts) #71'snext/imagework (width/height, lazy loading below the fold); add them if not. -
Measure. Add a docs article, a collection page and a large docs set (300+ pages, including the OpenAPI fixture from OpenAPI support #26) to the Lighthouse sample from Public sites perf · Phase 1: page weight (server-rendered blocks, lazy chat, images, fonts) #71. Set a JavaScript budget for docs pages and check it in CI.
Constraints for future docs features
- Syntax highlighting, when added, runs on the server and ships no highlighting code to the browser.
- New interactive docs widgets load on intent (idle, hover or click), like the chat widget in Public sites perf · Phase 1: page weight (server-rendered blocks, lazy chat, images, fonts) #71.
Done when
- Docs views, including the first view after a publish, are served from cache.
- Server render time and HTML size of a docs page don't depend on how many docs a team has.
- Docs pages meet the targets in
docs/site-delivery.md§9 (LCP < 1.5 s, CLS < 0.1, INP < 200 ms).
Activity
clbotdev commentedon Oct 26, 2026
Data from Oct 26 (06:00 IST), measured with curl from our agents' box:
x-nextjs-cache: HIT)/sites/<teamId>, host lookup, etc.).Separately, SendLit BA's local Lighthouse 12.8.2 runs (median of 3) on sendlit.app went from mobile 90 to 62 and desktop 92 to 56, with LCP 6.2–6.9 s on the hero h1. Lighthouse puts the root document at 660–690 ms. Unused JS grew from 50 to 72 KiB, which ties in with #56. The render-blocking CSS is #149, and the missing preconnect to cdn.medialit.cloud is still flagged. Some of this is measurement-network noise, but the TLS and cached-TTFB numbers above are consistent across runs.