diff --git a/AGENTS.md b/AGENTS.md index 26859bd..5d1c3a6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -116,7 +116,9 @@ components/ # client components: report-view, repo-list, # hero-search, menu-search, menu-toggle, breadcrumbs # (route trail under the menu), workflow-sample, # platform-config, sentry-provider, - # toast-notification (copy feedback live region) + # toast-notification (copy feedback live region), + # report-warmup (idle-time rendering-library + # warming on directory pages) lib/ # shared logic (client + RSC): routes, fetcher, # renderer, search, utils, host, rate-limiter, # cache-manager, error-handler, repo-submission, @@ -281,7 +283,15 @@ coverage there when introducing new markup patterns. the report's arrival causes no layout shift. The vizdom bridge (`public/widgets/vizdom-bridge.js`) serves the wasm from Cache Storage (versioned cache name) so repeat visits never re-download it regardless - of the host's HTTP cache headers. + of the host's HTTP cache headers. Directory pages (landing + user + listing) mount `components/report-warmup.jsx`, which — after window + load, at main-thread idle — warms the shared report rendering libraries + only (the vizdom bridge module/wasm, Chart.js + svg-pan-zoom no-cors + into the HTTP cache, the bundled template), never report data (listings + can hold thousands of repositories), so the first report a visitor opens + renders from local caches. The landing bundle budget e2e measures + through the window load event for this reason: post-load prefetches and + warm-up fetches never delay the landing's own first paint. - Search ``s are injected by table-enhancer — `` is FORBID in the renderer's sanitization allow-list, so it must never appear in the mustache template. diff --git a/README.md b/README.md index 386cf42..f80a011 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,8 @@ app/ # Next.js App Router (static export): layout components/ # Client components (search combobox, hero/menu # search, menu toggle, workflow sample, user # listing, report view, submission form, - # platform-config context, sentry provider) + # platform-config context, sentry provider, + # report warm-up for directory pages) lib/ # Shared logic consumed by client components and # RSC alike (routes, fetcher, renderer, search, # repo-submission, error-handler, rate-limiter, diff --git a/app/[username]/page.jsx b/app/[username]/page.jsx index 3d6615e..c5cc004 100644 --- a/app/[username]/page.jsx +++ b/app/[username]/page.jsx @@ -9,6 +9,7 @@ import { userStaticParams } from '../../lib/static-params'; import { reposForUser } from '../../lib/utils'; import { isValidGitHubName } from '../../lib/routes'; import RepoList from '../../components/repo-list'; +import ReportWarmup from '../../components/report-warmup'; export const dynamicParams = false; @@ -30,6 +31,11 @@ export default async function UserPage({ params }) { return ( Loading…

}> + {/* Directory page: warm the shared report rendering libraries during + idle time (vizdom wasm, Chart.js, svg-pan-zoom, the template — + never report data) so the first report a visitor opens renders + from local caches. */} +
); } diff --git a/components/landing.jsx b/components/landing.jsx index 59a16f8..c74f273 100644 --- a/components/landing.jsx +++ b/components/landing.jsx @@ -1,5 +1,6 @@ import Link from 'next/link'; import HeroSearch from './hero-search'; +import ReportWarmup from './report-warmup'; import { buildRepositoryListUrl } from '../lib/routes.js'; export const FEATURED_COUNT = 6; @@ -30,6 +31,11 @@ export default function Landing({ repositories }) { + {/* Directory page: warm the shared report rendering libraries during + idle time (vizdom wasm, Chart.js, svg-pan-zoom, the template — + never report data) so the first report a visitor opens renders + from local caches. Renders nothing; never delays this page. */} + ); } diff --git a/components/report-warmup.jsx b/components/report-warmup.jsx new file mode 100644 index 0000000..07d8782 --- /dev/null +++ b/components/report-warmup.jsx @@ -0,0 +1,127 @@ +'use client'; + +// Report rendering-library warm-up for directory pages (landing, user +// listing). Renders nothing; once the page has fully loaded AND the main +// thread is idle, it warms the shared rendering libraries the first report +// a visitor opens needs, so the report renders with them already in local +// caches: +// +// - vizdom wasm (~4.8MB): the shared bridge module is injected exactly the +// way the report page injects it, so the binary is fetched once and stored +// in the bridge's versioned Cache Storage entry — the report page's own +// bridge import then resolves it locally with zero network. +// - Chart.js + svg-pan-zoom: fetched no-cors into the HTTP cache; the +// report page's classic