feat(vite): live UI dashboard (svelteVitals({ ui: true })) - #49
Conversation
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…) in vite tests Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…eak the notify loop Final-review hardening: a client socket can error between its close event and the next fan-out write; wrap the write and remove the client on failure. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Warning Review limit reached
More reviews will be available in 14 minutes and 42 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (11)
📝 WalkthroughWalkthroughAdds an optional dev-only live UI for ChangesVite live UI dashboard
Sequence Diagram(s)sequenceDiagram
participant Browser
participant svelteVitalsHandle
participant installUiMiddleware
participant FindingsStore
Browser->>installUiMiddleware: GET /__svelte-vitals/
Browser->>installUiMiddleware: GET /__svelte-vitals/events
svelteVitalsHandle->>installUiMiddleware: POST /__svelte-vitals/ingest
installUiMiddleware->>FindingsStore: set(route, results)
FindingsStore-->>Browser: event: update
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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 |
There was a problem hiding this comment.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
docs/superpowers/specs/2026-06-23-vite-live-ui-design.md (1)
1-85: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winReflow this spec before landing.
CI is already reporting a Prettier failure on this file, so the markdown still needs a formatting pass.
🤖 Prompt for 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. In `@docs/superpowers/specs/2026-06-23-vite-live-ui-design.md` around lines 1 - 85, The Markdown spec needs a formatting-only reflow to satisfy Prettier before merging. Update the document’s prose and fenced blocks so the existing sections, lists, and code fences in the design doc are consistently wrapped and spaced without changing any content; use the spec’s section headings like “Architecture & data flow”, “Components”, and “Testing” as anchors while reformatting the entire file.Source: Pipeline failures
🤖 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 `@docs/src/content/docs/guides/dev-overlay.md`:
- Line 79: The CLI example in the dev-overlay guide is incomplete because it
shows only the flag instead of the full executable command. Update the
documentation text in the dev-overlay guide to replace the standalone reporter
flag with the full invocation using the svelte-vitals command, keeping the
existing context about whole-project reports and ensuring the example is
directly runnable.
In `@docs/src/content/docs/ja/guides/dev-overlay.md`:
- Line 79: Update the CLI example in the dev-overlay guide so it shows a
complete runnable command instead of the bare option; the current reference in
the documentation text around the global report invocation is incomplete. Use
the existing `npx svelte-vitals` example and make the HTML reporter form
explicit by combining it with `--reporter html`, so readers can copy a valid
command directly.
In `@docs/superpowers/plans/2026-06-23-vite-live-ui.md`:
- Around line 691-760: The new docs/release section in the plans markdown needs
reflow to satisfy Prettier formatting. Rewrap the long prose and list items in
the added “Live UI” steps so they follow the repo’s Markdown style, keeping the
content unchanged, and verify the section around the Step 1/2/3 blocks in the
plans document formats cleanly.
In `@packages/vite/src/hooks/handle.ts`:
- Around line 19-25: The outbound ingest request is currently built from
request-derived origin values, which can let server-side POSTs target unintended
hosts. Update postIngest and the call site in handle to stop using
event.url.origin directly; instead validate that the origin is a
loopback/dev-server origin (or replace it with a fixed configured dev origin)
before constructing the fetch URL. Keep the URL target constrained to the
trusted ingest host while preserving the existing ingest flow in postIngest.
In `@packages/vite/src/plugin.ts`:
- Around line 83-91: The configureServer setup in plugin.ts sets the
process-wide SVELTE_VITALS_UI flag but never clears it, so add teardown logic to
unset that flag when the dev server closes or middleware is removed. Update
configureServer and the related installUiMiddleware path so the UI-enabled state
is scoped to the active server lifecycle, and ensure the cleanup is mirrored by
the behavior expected in ui-plugin.test.ts.
In `@packages/vite/src/ui/middleware.ts`:
- Around line 32-35: The middleware in JSON ingestion is accepting malformed
finding objects because it only checks that results is an array before calling
store.set(). Update the parsing logic in middleware.ts so the route/results
payload is validated more strictly and only well-formed Result entries are
stored, using the existing store.set and renderDashboard flow as the reference
points. Reject any array items that do not match the expected Result shape
before persisting, so invalid payloads are ignored instead of reaching the
dashboard.
In `@packages/vite/test/ui-serve.test.ts`:
- Around line 6-8: The results fixture in ui-serve.test.ts is not formatted
according to Prettier, causing the CI warning; reformat the const results:
Result[] block so the object literal is split and aligned in the standard
multi-line style used elsewhere in the test file, keeping the same values but
adjusting only formatting.
In `@packages/vite/test/ui-store.test.ts`:
- Around line 5-7: The test helper r in ui-store.test.ts has a Prettier
formatting issue in the Result object literal; reformat this block to match the
project’s style so CI passes. Use the existing r helper and the surrounding test
setup as the location to apply the formatting-only fix, and run Prettier on the
file to ensure the object literal and line wrapping are normalized.
---
Outside diff comments:
In `@docs/superpowers/specs/2026-06-23-vite-live-ui-design.md`:
- Around line 1-85: The Markdown spec needs a formatting-only reflow to satisfy
Prettier before merging. Update the document’s prose and fenced blocks so the
existing sections, lists, and code fences in the design doc are consistently
wrapped and spaced without changing any content; use the spec’s section headings
like “Architecture & data flow”, “Components”, and “Testing” as anchors while
reformatting the entire file.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 1b19fd2d-7944-48f5-bf55-006e14b23ddc
📒 Files selected for processing (18)
.changeset/vite-live-ui.mddocs/src/content/docs/guides/dev-overlay.mddocs/src/content/docs/ja/guides/dev-overlay.mddocs/superpowers/plans/2026-06-23-vite-live-ui.mddocs/superpowers/specs/2026-06-23-vite-live-ui-design.mdpackages/vite/src/hooks/handle.tspackages/vite/src/plugin.tspackages/vite/src/ui/middleware.tspackages/vite/src/ui/serve.tspackages/vite/src/ui/store.tspackages/vite/test/integration.test.tspackages/vite/test/plugin-error.test.tspackages/vite/test/plugin-options.test.tspackages/vite/test/ui-ingest.test.tspackages/vite/test/ui-middleware.test.tspackages/vite/test/ui-plugin.test.tspackages/vite/test/ui-serve.test.tspackages/vite/test/ui-store.test.ts
Address CodeRabbit review on PR #49: - handle: only POST ingest to a loopback origin (event.url.origin is request-derived; a spoofed Host must not redirect the server-side POST off-box). - plugin: clear SVELTE_VITALS_UI when the dev server closes, so the handle doesn't keep POSTing after a restart / config flip. - middleware: validate ingested finding objects (id + detection) before store.set, so a malformed payload can't poison renderDashboard. - docs: spell out the full `npx svelte-vitals --reporter html` command (en + ja). - prettier: reformat the test fixtures + planning markdown CI flagged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds a dev-only, live-updating HTML dashboard to @svelte-vitals/vite (enabled via svelteVitals({ ui: true })) that reuses the core HTML renderer and updates as you navigate during vite dev, with findings fed from the existing svelteVitalsHandle over HTTP.
Changes:
- Introduces a dev-server UI middleware (
/__svelte-vitals/,/ingest,/events) backed by an in-memory findings store and SSE updates. - Extends the Vite plugin to optionally return a second
apply: 'serve'plugin that mounts the UI and sets/clearsSVELTE_VITALS_UI. - Updates the dev
handleto POST route findings to the dev server when the UI flag is enabled; adds tests, docs, and a minor changeset.
Reviewed changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| packages/vite/src/ui/store.ts | Adds an in-memory per-route findings store with snapshot + subscriptions. |
| packages/vite/src/ui/serve.ts | Renders the dashboard via core buildHtmlDocument and injects a live-update script. |
| packages/vite/src/ui/middleware.ts | Mounts dashboard/ingest/SSE routes on the Vite dev server. |
| packages/vite/src/plugin.ts | Adds ui?: boolean; returns [buildPlugin, uiPlugin] in dev when enabled. |
| packages/vite/src/hooks/handle.ts | Env-gated POST of analyzed route results to /__svelte-vitals/ingest. |
| packages/vite/test/ui-store.test.ts | Unit tests for the findings store behavior. |
| packages/vite/test/ui-serve.test.ts | Unit tests for dashboard HTML rendering + script injection. |
| packages/vite/test/ui-middleware.test.ts | Tests ingest → dashboard rendering and ingest → SSE update behavior. |
| packages/vite/test/ui-plugin.test.ts | Tests svelteVitals({ ui }) plugin shape and server wiring behavior. |
| packages/vite/test/ui-ingest.test.ts | Tests that the handle POSTs only when SVELTE_VITALS_UI is set (and blocks non-loopback). |
| packages/vite/test/plugin-options.test.ts | Adjusts types/casts due to `Plugin |
| packages/vite/test/plugin-error.test.ts | Adjusts types/casts due to `Plugin |
| packages/vite/test/integration.test.ts | Adjusts types/casts due to `Plugin |
| docs/src/content/docs/guides/dev-overlay.md | Documents the new Live UI dashboard (EN). |
| docs/src/content/docs/ja/guides/dev-overlay.md | Documents the new Live UI dashboard (JA). |
| docs/superpowers/specs/2026-06-23-vite-live-ui-design.md | Adds design spec for the live UI mode. |
| docs/superpowers/plans/2026-06-23-vite-live-ui.md | Adds implementation plan for the live UI mode. |
| .changeset/vite-live-ui.md | Declares a minor release for @svelte-vitals/vite with the live UI feature. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Per Copilot review on PR #49: isResultLike now also requires a string message, a valid severity (critical|warning|info), and string detection.presence/value — so a partial object (e.g. {id, detection:{}}) can't reach escapeHtml(title) / effectiveSeverity and crash the dashboard. Tests cover the new reject cases.
… feed visibility - decode ingest body via Buffer.concat so multibyte chars split across chunks don't corrupt JSON and silently drop a route's findings - end open SSE connections on dev-server close so httpServer.close() can finish (open keep-alive streams would otherwise hang vite restart/shutdown) - log skipped ingest for non-loopback origins under SVELTE_VITALS_DEBUG and document the loopback-only behavior (en/ja) so --host users know why the dashboard stays empty Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a live UI dashboard to
@svelte-vitals/vite— sub-project B of the "Lighthouse-like visualization" pillar.svelteVitals({ ui: true })serves a svelte-vitals report at/__svelte-vitals/duringvite devthat updates live as you navigate, reusing the same renderer as the CLI's--reporter html(shipped in #47).How it works
svelteVitalsHandle(already inhooks.server.tsfor the dev overlay) analyzes each visited page's rendered<head>. When the UI is enabled, it also POSTs the route's findings to the dev server (/__svelte-vitals/ingest) — fire-and-forget, errors swallowed.buildHtmlDocument(buildJsonReport(...))at/__svelte-vitals/, with a small live-update script injected before</body>. It pushes SSEupdateevents; the page re-fetches and swaps.wrapin place (scroll/filters preserved, no full reload).process.env.SVELTE_VITALS_UI.Setup (two files, same as the dev overlay)
Open
http://localhost:5173/__svelte-vitals/and browse your app.Reuse / boundaries
@svelte-vitals/coreis unchanged — the UI only consumesbuildHtmlDocument/buildJsonReport.buildHtmlDocumentis reused verbatim; the live behavior is the injected<script data-live>only (vite-side).@svelte-vitals/vite. No dependency on the CLI. No new runtime dependencies (Node built-ins + vite peer types). ESM-only.svelteVitals()withoutuireturns the same single build plugin (byte-for-byte), and the handle does not POST when the flag is unset — dev-overlay-only users are unaffected.Scope (honest, rendered model)
Like the dev overlay, this is dev-only and rendered-based: it covers SEO
<head>rules for the routes you visit (accumulates as you browse). Performance image rules and project-wide checks (robots/sitemap) aren't covered by this mode, and Health reflects visited routes. For a whole-project report, usenpx svelte-vitalsor--reporter html. (Manifest-all listing and deeper coverage are noted as follow-ups in the spec.)Release
@svelte-vitals/viteminor changeset only (no core/cli change).Validation
pnpm -r typecheck,pnpm -r test(vite 45 incl. new store/serve/middleware/plugin/ingest tests; 287 total),pnpm build,pnpm --filter docs build(39 pages),pnpm lint, publint — all green.attwfails locally only (sandboxnpm pack) — known pre-existing, CI-unaffected.Process
Built subagent-driven: 6 tasks (each spec + quality reviewed) + a whole-branch review on Opus (verdict: ready to merge). A cross-task typecheck/lint fix (the
Plugin | Plugin[]return type rippling into existing vite tests, and ano-explicit-anyin the new middleware test) and a final SSE-client-cleanup hardening were applied and re-verified. Docs: dev-overlay guide gains a "Live UI" section (en + ja).🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
/__svelte-vitals/when enabled.Bug Fixes
Documentation