Skip to content

perf: lazy-load and cache frontend assets - #344

Merged
mira-2026 merged 8 commits into
mainfrom
perf/frontend-bundle-asset-caching
Jul 28, 2026
Merged

perf: lazy-load and cache frontend assets#344
mira-2026 merged 8 commits into
mainfrom
perf/frontend-bundle-asset-caching

Conversation

@mira-2026

@mira-2026 mira-2026 commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • lazy-load all 16 page routes and preload navigation targets on intent
  • lazy-load chat markdown, replace the full syntax bundle with an explicit Highlight.js language set, and use the Monokai Sublime palette
  • add checked-in gzip bundle budgets, build metrics, and deterministic Brotli/gzip precompression
  • serve HTML and unhashed files with revalidation while serving hashed assets as one-year immutable content
  • add ETag, Last-Modified, conditional 304 handling, and negotiated compressed representations
  • resize the dedicated browser favicon from 246,704 bytes at 512×512 to 11,147 bytes at 96×96
  • recover safely when the managed PR-preview path exists as an empty, unregistered directory
  • keep direct source-mode development ready when a generated release manifest remains in the worktree

Behavior and regression coverage

The production build now reports:

  • initial JavaScript: 899,304 bytes raw / 285,311 bytes gzip
  • total JavaScript: 2,375,053 bytes raw / 741,180 bytes gzip
  • largest JavaScript output: 68,490 bytes gzip
  • initial stylesheet: 138,572 bytes raw / 19,294 bytes gzip

The review baseline was approximately 1.78 MB / 533 KB gzip for the eager entry bundle. Route and chat-heavy dependencies now load on demand. Navigation hover/focus preloads the target route to avoid adding avoidable interaction latency.

Static server regression coverage verifies HTML revalidation, immutable hashed caching, Brotli/gzip negotiation (including quality values), ETag and Last-Modified 304 responses, decompression, missing-asset behavior, and rejection of direct sidecar URLs. Bundle helper tests cover static-vs-dynamic graph accounting, valid compressed outputs, fail-closed metadata handling, and budget failures.

Already-open tabs recover from deployment-removed lazy chunks with one guarded hard reload on committed navigation, limited to known dynamic-import loading failures; ordinary module evaluation errors surface without reloading. Speculative hover/focus preload failures remain silent. Repeat navigation failures surface normally instead of looping. When lazy chat markdown commits, it also notifies the sticky-scroll controller so a changed row height is settled correctly.

Managed PR dev now removes only an empty preview path after pruning any stale Git worktree registration, then lets git worktree add recreate it. Non-empty or unsafe paths continue to fail closed.

Direct source-mode development now uses the existing Git fallback before considering ignored release artifacts. Only a missing manifest can use the non-production fallback; missing or changed declared artifacts remain manifest-invalid. Production and bundled runtimes continue to verify the complete release manifest and embedded build identities strictly.

Visible UI change: syntax-highlighted code uses the Monokai Sublime palette, with the matching Okaidia/Prism palette for GraphQL; application layout and behavior are otherwise unchanged.

Verification

  • Frontend lint: bun run lint:frontend
  • Frontend build: bun run build:frontend
  • Frontend tests: bun test — 498 passed
  • Backend lint: bun run lint:backend
  • Backend build: bun run build:backend
  • Backend tests: bun test — 606 passed
  • Focused regression tests: frontend bundle helpers, lazy-import recovery and chat scroll settlement, static HTTP delivery, empty/stale managed preview paths, and source-mode release identity
  • Release packaging: bun run release:manifest — 236 artifacts, including 136 compressed representations
  • Managed PR-dev lifecycle smoke: start/ready/stop with unit, listener, route, and credential cleanup verified
  • Direct HMR lifecycle smoke: worktree source mode reached full readiness through the Tailscale URL, then removed its processes, listeners, and route on clean shutdown
  • Manual browser rendering smoke: not run; route rendering, code views, response bodies, compression, and headers are covered by the full suites and production build

Risk checklist

  • No secrets, tokens, .env files, database dumps, or runtime state committed
  • Static file paths, symlinks, hidden paths, and direct compressed-representation access were reviewed carefully
  • No new API route or authentication boundary
  • No migration or persistent data-shape change
  • No runtime/reconnect ordering change
  • UI change is described above

Deployment / operations

  • Standard Dashboard deploy/restart needed after merge so the web process serves the new headers and compressed assets
  • No config or secret changes needed
  • Rollback uses the existing immutable previous release slot

Notes for reviewers

Please focus on the initial-graph traversal/budgets, static representation negotiation/conditional request semantics, guarded lazy-import recovery, and the two development-path recovery changes.

Docs: not needed — this changes internal bundling, HTTP delivery, and development recovery behavior without changing user-facing or operator contracts, configuration, or runbooks.

@mira-2026
mira-2026 requested a review from rajohan as a code owner July 28, 2026 05:46
@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds frontend bundle measurement and precompression, shared static-file negotiation with HTTP caching, lazy route and markdown loading with recovery, shared syntax highlighting, route preloading, release identity handling, preview worktree cleanup, and expanded tests.

Changes

Static asset delivery

Layer / File(s) Summary
Build artifact measurement and compression
scripts/frontendBuild.ts, scripts/frontendBuildArtifacts.ts, src/test/frontendBuildArtifacts.test.ts
Production builds emit metafiles, measure and budget bundles, write metrics, and generate Brotli/gzip sidecars.
Negotiated static file responses
backend/src/staticFileResponse.ts
Static responses negotiate compressed representations, set validators and cache headers, and return conditional 304 responses.
Server static-file routing and validation
backend/src/server.ts, backend/test/*
Static routing applies hashed-asset cache policies, rejects direct sidecar requests, and tests negotiation and revalidation.

Frontend loading and rendering

Layer / File(s) Summary
Shared syntax highlighting
src/lib/syntaxHighlighter.tsx, src/components/features/chat/ChatMarkdown.tsx, src/components/features/files/viewers/CodePreview.tsx, src/test/componentBehavior.test.tsx
A shared highlighter supports registered languages and GraphQL Prism rendering.
Lazy route and markdown loading
src/lib/routeModules.ts, src/lib/lazyImportRecovery.ts, src/router.tsx, src/components/features/chat/ChatMessagesList.tsx, src/components/layout/Layout.tsx, src/test/lazyImportRecovery.test.ts
Routes and markdown load dynamically, navigation preloads routes, and failed imports use guarded reload recovery with Suspense fallbacks.
Document shell metadata
index.html
The favicon link declares a 96x96 icon size.

Runtime identity and preview worktrees

Layer / File(s) Summary
Development release identity resolution
backend/src/releaseManifest.ts, backend/test/releaseManifest.test.ts
Development identities use centralized Git-derived fallback handling, while non-development manifest failures report readiness and issue fields consistently.
Preview worktree cleanup and recreation
backend/src/services/pullRequestPreviewHost.ts, backend/test/pullRequestPreview.test.ts
Managed worktrees unregister stale paths, remove empty directories, and are recreated under updated lifecycle conditions.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Browser
  participant BunServer
  participant staticFileResponse
  participant FrontendAssets
  Browser->>BunServer: request asset with Accept-Encoding
  BunServer->>staticFileResponse: resolve file and cache policy
  staticFileResponse->>FrontendAssets: inspect source and sidecars
  FrontendAssets-->>staticFileResponse: return selected representation
  staticFileResponse-->>Browser: encoded response or 304
Loading
sequenceDiagram
  participant User
  participant Layout
  participant routeModules
  participant Router
  participant loadLazyModule
  User->>Layout: focus or hover route link
  Layout->>routeModules: preload route module
  User->>Router: navigate to route
  Router->>loadLazyModule: load route component
  loadLazyModule-->>Router: resolve module or initiate guarded reload
Loading

Possibly related PRs

Suggested labels: type: tests

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title is concise and matches the main changes: lazy-loading and caching frontend assets.
Description check ✅ Passed The description follows the template well and covers summary, behavior, verification, risk, deployment, and reviewer notes.

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@mira-2026 mira-2026 added priority: medium Normal-priority planned work status: needs-review Ready for human or agent review type: performance Performance, resource usage, or responsiveness work area: frontend Frontend UI, client state, routing, and browser behavior area: backend Backend API, server routes, services, and integrations area: ci CI, test runners, workflow checks, and release gates labels Jul 28, 2026
@codecov

codecov Bot commented Jul 28, 2026

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a1734da7eb

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/components/features/chat/ChatMessagesList.tsx Outdated
Comment thread src/router.tsx Outdated
@mira-2026

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4add2941c8

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/components/layout/Layout.tsx Outdated
Comment thread src/lib/syntaxHighlighter.tsx
@mira-2026

Copy link
Copy Markdown
Collaborator Author

@codex review

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/features/chat/ChatMessagesList.tsx`:
- Around line 47-53: Update SettledChatMarkdown so onLoadReference.current is
refreshed inside an effect rather than during render, and make the layout effect
depend on text so markdown changes trigger re-measurement. Preserve the existing
onLoad callback invocation while ensuring the latest callback is used.

In `@src/lib/lazyImportRecovery.ts`:
- Around line 87-90: Update the cooldown check in the lazy import reload
recovery logic to require a non-negative elapsed duration before treating
lastReloadAt as within the cooldown, so future timestamps do not suppress
recovery. Add a regression test covering a lastReloadAt later than now and
verify reload recovery proceeds.

In `@src/lib/syntaxHighlighter.tsx`:
- Around line 32-33: Update the GraphQL highlighting path in
PrismSyntaxHighlighter so it uses the requested monokaiSublime theme
consistently with file and chat code blocks instead of always applying okaidia;
remove the unused okaidia import and preserve the existing GraphQL language
registration.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f4e8a930-3528-4044-a7c0-bb4bf0e70ef2

📥 Commits

Reviewing files that changed from the base of the PR and between a1734da and 0a2d876.

📒 Files selected for processing (8)
  • src/components/features/chat/ChatMessagesList.tsx
  • src/components/layout/Layout.tsx
  • src/lib/lazyImportRecovery.ts
  • src/lib/routeModules.ts
  • src/lib/syntaxHighlighter.tsx
  • src/router.tsx
  • src/test/componentBehavior.test.tsx
  • src/test/lazyImportRecovery.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/router.tsx
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
  • GitHub Check: Analyze JavaScript and TypeScript
  • GitHub Check: frontend-checks
  • GitHub Check: backend-checks
🧰 Additional context used
🪛 React Doctor (0.7.6)
src/components/features/chat/ChatMessagesList.tsx

[error] 49-49: This ref is mutated during render. React can replay or discard render work, so the mutation can leak from UI that never commits.

Move ref writes into an event handler or effect. Render must stay pure because React can replay or discard it. The predictable null-guarded lazy initialization pattern remains supported.

(no-ref-current-in-render)

🔇 Additional comments (8)
src/lib/routeModules.ts (1)

1-53: LGTM!

src/lib/lazyImportRecovery.ts (1)

1-86: LGTM!

Also applies to: 94-105

src/components/layout/Layout.tsx (1)

28-28: LGTM!

Also applies to: 115-116

src/test/lazyImportRecovery.test.ts (1)

1-181: LGTM!

src/lib/syntaxHighlighter.tsx (1)

1-5: LGTM!

Also applies to: 64-71

src/test/componentBehavior.test.tsx (1)

2618-2618: LGTM!

Also applies to: 2689-2689, 2843-2849

src/components/features/chat/ChatMessagesList.tsx (2)

14-26: LGTM!


707-718: LGTM!

Comment thread src/components/features/chat/ChatMessagesList.tsx Outdated
Comment thread src/lib/lazyImportRecovery.ts
Comment thread src/lib/syntaxHighlighter.tsx Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0a2d8765ce

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/lib/lazyImportRecovery.ts
Comment thread scripts/frontendBuildArtifacts.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/src/releaseManifest.ts`:
- Around line 802-805: Restrict the development fallback in the release-loading
flow around isDevelopmentFallback to ENOENT errors raised during manifest lookup
only. Track the current failure phase or isolate manifest loading from artifact
and build-identity verification, so missing artifacts during verification
continue through the non-ready issue-reporting path instead of returning
developmentRuntimeReleaseIdentity with ready: true.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: fac94042-1f2d-47e4-9ee2-72bf54874351

📥 Commits

Reviewing files that changed from the base of the PR and between 0a2d876 and a4c21a4.

📒 Files selected for processing (11)
  • backend/src/releaseManifest.ts
  • backend/src/services/pullRequestPreviewHost.ts
  • backend/test/pullRequestPreview.test.ts
  • backend/test/releaseManifest.test.ts
  • scripts/frontendBuildArtifacts.ts
  • src/components/features/chat/ChatMessagesList.tsx
  • src/lib/lazyImportRecovery.ts
  • src/lib/syntaxHighlighter.tsx
  • src/test/componentBehavior.test.tsx
  • src/test/frontendBuildArtifacts.test.ts
  • src/test/lazyImportRecovery.test.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/test/componentBehavior.test.tsx
  • src/lib/lazyImportRecovery.ts
  • scripts/frontendBuildArtifacts.ts
  • src/components/features/chat/ChatMessagesList.tsx
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
  • GitHub Check: frontend-checks
  • GitHub Check: backend-checks
  • GitHub Check: Analyze JavaScript and TypeScript
🧰 Additional context used
🪛 ast-grep (0.44.1)
src/test/frontendBuildArtifacts.test.ts

[warning] 140-140: Filesystem path is not a string literal; a request-/variable-derived path can enable path traversal. Validate and normalize the path before use.
Context: fs.writeFile(path.join(outdir, "assets", "entry.js"), entryContents)
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(detect-non-literal-fs-filename-typescript)

🔇 Additional comments (7)
src/lib/syntaxHighlighter.tsx (1)

33-33: LGTM!

Also applies to: 66-90, 108-112

src/test/lazyImportRecovery.test.ts (1)

1-17: LGTM!

Also applies to: 19-28, 30-40, 42-60, 62-101, 103-127, 129-153, 155-205, 207-227

backend/src/releaseManifest.ts (1)

739-747: LGTM!

Also applies to: 754-756

backend/test/releaseManifest.test.ts (1)

583-600: LGTM!

backend/src/services/pullRequestPreviewHost.ts (1)

15-15: LGTM!

Also applies to: 600-632, 645-649, 717-724, 748-748

backend/test/pullRequestPreview.test.ts (1)

514-519: LGTM!

Also applies to: 632-638, 718-721, 822-823, 833-842

src/test/frontendBuildArtifacts.test.ts (1)

138-164: LGTM!

Comment thread backend/src/releaseManifest.ts Outdated
@mira-2026
mira-2026 merged commit 195e665 into main Jul 28, 2026
7 checks passed
@mira-2026
mira-2026 deleted the perf/frontend-bundle-asset-caching branch July 28, 2026 08:53
mira-2026 added a commit that referenced this pull request Jul 28, 2026
## Summary

- resolve the single generated JavaScript output that owns
`src/main.tsx`
- repair Bun's generated module-script target when HTML-entry builds
with splitting and metafile output point at an unrelated shared chunk
- fail closed on ambiguous app outputs or module scripts, and measure
the initial bundle from the real application graph

## Production incident

The deployment of PR #344 (`195e665d`) passed service health checks but
served an empty `#root`. Its generated `index.html` loaded a 1.7 kB
shared `Switch` chunk instead of the application bootstrap. Production
was rolled back successfully to `96f613d2` before this hotfix.

## Verification

- `bun run lint:frontend`
- `bun test src/test/frontendBuildArtifacts.test.ts` — 6 passed
- `bun test` — 499 passed
- `bun run build:frontend`
- `bun run build:backend`
- `bun run release:manifest` — 236 artifacts, both component identities
on `2347976e`
- clean-build browser smoke rendered the login page with no console
errors

Docs: not needed — this is an internal build-output correctness fix with
no configuration, API, or operator-contract change.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: backend Backend API, server routes, services, and integrations area: ci CI, test runners, workflow checks, and release gates area: frontend Frontend UI, client state, routing, and browser behavior priority: medium Normal-priority planned work status: needs-review Ready for human or agent review type: performance Performance, resource usage, or responsiveness work

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants