Skip to content

perf(dashboard): Serve styles, fonts, and avatar as hashed static assets - #2757

Merged
BYK merged 2 commits into
mainfrom
perf/dashboard-static-css
Nov 5, 2026
Merged

BYK merged 2 commits into
mainfrom
perf/dashboard-static-css

Conversation

@sentry-junior

@sentry-junior sentry-junior Bot commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

The page shell had the full Tailwind stylesheet (177 KB raw / 28 KB gzip) inline in every no-store HTML response. It also loaded Inter and Outfit through a render-blocking Google Fonts @import, which needs two more origins. The header and transcript avatar was a 76 KB PNG that was not hashed.

  • The client build now bundles src/styles.css (self-hosted fontsource variable fonts + dist/tailwind.css) into styles-[hash].css. The fonts are *-[hash].woff2 files under /_junior/dashboard/assets, the same immutable prefix as the JS from perf(dashboard): Serve dashboard browser files as static assets #2725. Fonts keep font-display: swap.
  • The shell links the stylesheet and preloads the two Latin font files. The other subsets load only when a page uses them. The forbidden page uses the same stylesheet link.
  • The avatar is an 88×88 (2× of size-11) hashed WebP: 3.2 KB. No PNG fallback, because every supported browser decodes WebP. /_junior/dashboard/avatar.png stays for older cached clients and the install icons.
  • Binary public assets are embedded as base64 and served with the content type from their extension.
  • Core no longer copies tailwind.css into server output. Nothing reads it now.

Numbers (/conversations, mock conversations, production build)

before after
HTML raw / gzip / br 189,104 / 31,888 / 24,789 B 11,141 / 2,902 / 2,292 B
Third-party origins fonts.googleapis.com, fonts.gstatic.com none
Render-blocking chain HTML → Google CSS → gstatic woff2 HTML → hashed CSS (fonts preloaded in parallel)
modulepreload links 58 58 (unchanged, see below)
Avatar 76,539 B PNG, revalidated 3,206 B WebP, immutable
Cold first load, same-origin br (HTML + head assets) 498,513 B 580,255 B

On a cold load, the first-load figure goes up because the CSS (23 KB br) and the Latin fonts (48 + 32 KB) now come from our origin instead of Google. The browser fetched about the same font bytes from gstatic before. On every later load, all of that is cached as immutable, so the HTML is the only transfer: 24.8 KB → 2.3 KB br.

Not in this PR: merging small chunks

esbuild has no minimum chunk size and no manual chunk grouping. 37 of the 58 preloaded chunks are under 4 KB, and 19 are under 1 KB. In an experiment, rolldown 1.2.15 with default splitting gave 21 static imports instead of 58 and 419,654 B br instead of 473,724 B, with the route splitting from #2734/#2738 kept. That needs the client build moved from tsup to rolldown and checked at runtime, so it is a separate follow-up.

Screenshots (mock conversations, 1440×900, dark)

The screenshots should look the same. Fonts loaded before: Inter 400/500/600/700, Outfit 500 from Google. After: Inter Variable 100–900, Outfit Variable 100–900 from the assets prefix.

before after
before transcript after transcript
before conversations after conversations

Header avatar at 4× zoom, PNG (left) and WebP (right):

avatar compare

Checks

  • pnpm test:e2e:dashboard (playwright, local chromium): 100 passed
  • pnpm --filter @sentry/junior-dashboard test: 370 passed, 1 failed. The failure is dashboard-output.test.ts. It also fails on clean main in this sandbox: the nitro build reports MISSING_EXPORT nitroIntegration from a hoisted @sentry/server-utils@11.6.0. CI should run it.
  • nitro-plugin-module.test.ts and app-config.test.ts: 42 passed
  • typecheck (dashboard, core), dashboard and core oxlint, file-length, dashboard-style, test-architecture, package:lint, and the pre-push pnpm lint: pass

via @BYK.

--

View Session in Sentry

The page shell inlined the full Tailwind stylesheet (177 KB) into every
no-store HTML response and loaded Inter and Outfit from Google Fonts
through a render-blocking @import on two extra origins.

The client build now bundles the stylesheet with self-hosted variable
fonts into content-hashed files under /_junior/dashboard/assets. The
shell links the stylesheet and preloads the Latin font files. The avatar
in the header and transcript is now an 88x88 hashed WebP (3 KB instead
of the 76 KB PNG). Core no longer copies tailwind.css into server output.

Co-Authored-By: BYK <126780+BYK@users.noreply.github.com>
@github-actions github-actions Bot added the risk: high PR risk score: high label Nov 5, 2026
…-css

# Conflicts:
#	packages/junior-dashboard/src/client/conversations/TranscriptMessageShell.tsx
@BYK
BYK enabled auto-merge (squash) November 5, 2026 18:14
@github-actions

github-actions Bot commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

20 screenshot changes — 20 changed · 0 added · 0 removed

Review screenshots in Frameshift

Automation Page Light · Desktop
Automation Page Light · Desktop
Changed
Automation Run Details · Desktop
Automation Run Details · Desktop
Changed
Automation Run Details Light · Desktop
Automation Run Details Light · Desktop
Changed
Conversation Attachment Modal · Desktop
Conversation Attachment Modal · Desktop
Changed
Conversation Child Agent Drawer · Desktop
Conversation Child Agent Drawer · Desktop
Changed
Conversation Event Log Virtual · Mobile
Conversation Event Log Virtual · Mobile
Changed
Show 12 more changed screenshots
Conversation Fork Dialog · Desktop
Conversation Fork Dialog · Desktop
Changed
Conversation Long Transcript Touch · Mobile
Conversation Long Transcript Touch · Mobile
Changed
Conversation Queue Compact · Desktop
Conversation Queue Compact · Desktop
Changed
Conversation Share Details · Desktop
Conversation Share Details · Desktop
Changed
Conversation Sidebar Review Chip · Desktop
Conversation Sidebar Review Chip · Desktop
Changed
Conversation Sidebar Review Chip Light · Desktop
Conversation Sidebar Review Chip Light · Desktop
Changed
Conversation Unsent Answers · Desktop
Conversation Unsent Answers · Desktop
Changed
Conversations Pinned Light · Desktop
Conversations Pinned Light · Desktop
Changed
Locations · Desktop
Locations · Desktop
Changed
People · Desktop
People · Desktop
Changed
Review Desk Light · Desktop
Review Desk Light · Desktop
Changed
Settings Mcp · Desktop
Settings Mcp · Desktop
Changed

2 more changed screenshots in Frameshift.

@BYK
BYK merged commit 6da128c into main Nov 5, 2026
45 checks passed
@BYK
BYK deleted the perf/dashboard-static-css branch November 5, 2026 18:23
@vercel

vercel Bot commented Nov 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
junior-docs Ready Ready Preview Nov 5, 2026 6:29pm UTC

Request Review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk: high PR risk score: high

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant