Skip to content

feat(inspector): rebuild on devframe - #5276

Merged
antfu merged 14 commits into
unocss:mainfrom
antfubot:feat/inspector-devframe
Sep 4, 2026
Merged

antfu merged 14 commits into
unocss:mainfrom
antfubot:feat/inspector-devframe

Conversation

@antfubot

Copy link
Copy Markdown
Contributor

Description

Rebuilds the UnoCSS Inspector on devframe, replacing the hand-rolled REST API (/__unocss_api) and sirv static serving — and resolving the long-standing TODO: migrate to Vite DevTools and use it's RPC layer.

Server

  • One portable DevframeDefinition with a typed RPC layer under the unocss scope: get-project-info, get-module-info, generate-repl, get-overview (compile-time typing via RpcDefinitionsToFunctionsWithNamespace, no runtime schemas).
  • Change notifications are pushed over devframe broadcasts (on-module-updated, on-config-changed, on-invalidated) wired to the plugin's handleHotUpdate / ctx.onReload / ctx.onInvalidate (debounced), replacing the client's dynamic /@vite/client HMR import.
  • UnocssInspector(ctx) keeps its signature (now returning Plugin[]), and inspector: false keeps working.

Hosting (dual-host)

  • Vite DevTools dock via createPluginFromDevframe — mounted by the @vitejs/devtools host at /__unocss-devtools/, auto-trusted inside the dock (no prompt). Static DevTools builds bake a pre-computed RPC dump of the inspector data (project/overview snapshots + per-module records), viewable with no dev server.
  • Standalone /__unocss/ stays for plain-Vite users (deprecated surface): SPA + RPC/WS bridged into Vite's own HTTP server, gated by devframe's one-time-code auth with an in-SPA unlock screen (also serves the Nuxt DevTools tab iframe). When the Vite DevTools host is active, top-level visits redirect to the DevTools UI.
  • Any devframe host via the new @unocss/inspector/devframe export: createInspectorDevframe(ctx) binds to an existing UnoCSS context; createStandaloneInspectorDevframe() builds a standalone context by scanning project files (for hosts without a bundler-integrated context, e.g. Next.js + @unocss/postcss through @devframes/next).

Client

  • The Vue SPA is kept intact; the data layer swaps useFetch-over-REST for connectDevframe() RPC with reactive query wrappers, event-driven refetching, and a reconnect loop (devframe clients don't reconnect on their own).
  • New auth screen (AuthGate.vue) for the OTP flow outside the DevTools dock.
  • Built with a relative base so one build serves at /__unocss/, the DevTools dock base, or any other mount.

Playgrounds

  • examples/inspector-vite — plain Vite, standalone URL + OTP.
  • examples/inspector-vite-devtools — Vite DevTools embedded dock (dev) and static DevTools export with the baked RPC dump (vite build).
  • examples/inspector-next — Next.js hosting the inspector via @devframes/next, no Vite involved.

All three verified end-to-end in a browser (auth, overview/module/REPL queries, live update pushes, dock auto-trust, static dump).

Notes

  • devframe / @devframes/vite / @vitejs/devtools-kit are pinned to the aligned ^0.9.5 / ^0.6.0 pairing.
  • The undocumented internal REST endpoints are removed; the standalone surface gains the auth gate (matching devframe's security model).
  • Includes Vitest coverage for the RPC handlers and devframe wiring (test/inspector.test.ts).

This PR was created with the help of an agent.

@antfubot
antfubot requested review from antfu and zyyv as code owners August 24, 2026 08:05
@netlify

netlify Bot commented Aug 24, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for unocss ready!

Built without sensitive environment variables

Name Link
🔨 Latest commit aa8b832
🔍 Latest deploy log https://app.netlify.com/projects/unocss/deploys/6a9a316a1adfe900087f81f1
😎 Deploy Preview https://deploy-preview-5276--unocss.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@antfu
antfu marked this pull request as draft August 24, 2026 21:56
Replace the inspector's hand-rolled REST API and sirv static serving with
devframe: a typed RPC layer (project-info, module-info, repl, overview) over
WebSocket, server-pushed change notifications, and multiple hosting surfaces
from a single portable definition.

- Vite DevTools dock via @vitejs/devtools-kit's createPluginFromDevframe,
  auto-trusted inside the DevTools host, with the inspector data baked into
  static DevTools builds as a pre-computed RPC dump
- Standalone /__unocss surface kept (deprecated), now gated by devframe's
  one-time-code auth with an in-SPA unlock screen; redirects to the Vite
  DevTools UI when the host is active
- Live updates now ride devframe broadcasts instead of the /@vite/client
  HMR hack, with automatic reconnection
- New @unocss/inspector/devframe export: createInspectorDevframe(ctx) and
  createStandaloneInspectorDevframe() for non-Vite hosts (e.g. Next.js via
  @devframes/next)
- Playgrounds: examples/inspector-vite, examples/inspector-vite-devtools
  (dev dock + static build), examples/inspector-next
- Vitest coverage for the RPC layer and devframe wiring
The new `@unocss/inspector/devframe` subpath had no node10 type
resolution, failing `attw` in CI (publint/attw run only when CI=true).
Mirror the `typesVersions` wildcard map used across the monorepo.
A cold deploy build could race on a lazily-loaded language
("Language `html` not found"), failing the Netlify docs deploy
intermittently. Preload the grammars the twoslash transformers rely on.
Register `@devframes/service-shiki` on the definition (declared lazily by
package name, so the host imports it from the inspector's deps and merges
languages with any host-provided instance). Read-only CSS output panes now
render server-highlighted dual-theme HTML through the service via a new
`ShikiCode` component, degrading to plain text when the service is absent
(e.g. static builds). The editable REPL input and matched-token source
views keep CodeMirror.
@antfubot
antfubot force-pushed the feat/inspector-devframe branch from 277272c to 3d42b74 Compare August 27, 2026 06:11
@pkg-pr-new

pkg-pr-new Bot commented Aug 27, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

commit: aa8b832

antfu and others added 10 commits September 1, 2026 14:08
`dev:client` served the SPA with no RPC backend, so it sat forever on
"Connection lost — reconnecting". Start a standalone devframe backend
(auth-less, single-user localhost) alongside it, scanning the inspector's
own sources for something to inspect. The client connects to it directly
over an absolute URL with the connection descriptor injected — Vite's proxy
mangles devframe's WebSocket frames and breaks its SSE session correlation,
so a direct cross-origin connection is used instead. Guarded on globalThis
so Vite reloads reuse the one instance, and degrades gracefully (with a hint
to build first) when the package's dist isn't available.
The sidebar hid a tree group that had only root-level files (no nested
folders), and the vanilla examples kept all their markup in `index.html`
plus plain `.ts` modules — which UnoCSS skips by default — so only one
module was ever tracked. Render a group when it has files OR folders, give
the examples a small multi-file `src/` structure, and opt their `.ts`
modules into the content pipeline so the tree reflects the whole app (like
the Next.js example, whose standalone scan already covers every file).
Replace the custom server broadcasts + typed client-function augmentation +
client event hooks + reconnect-refetch wiring with a single devframe shared
state ('changes'): the server bumps a revision, the client watches it to
refetch. A reconnecting client gets the latest snapshot for free, so stale
data self-heals without bespoke reconnection plumbing — less code and a
smaller maintenance surface.
The standalone /__unocss/ RPC bridge inherited devframe's loopback-only WS
origin check, so the upgrade was refused (403) whenever the dev server is
reached at a non-loopback origin — `vite --host`, containers, WSL, tunnels —
leaving the inspector stuck on "Connecting…". `devframeViteBridge` exposes no
way to override it, so mount the RPC backend via `initDevframe` directly with
`allowedOrigins: false`. The endpoint is served same-origin by the dev server
and the one-time-code gate is the real trust boundary, so the origin check
added nothing here.
Swap the sidebar file icons to the catppuccin set (per @antfu/design's
DisplayFileIcon), rendered through an `icon-catppuccin` shortcut that
inverts/rehues/dims the dark-tuned glyphs on a light surface and cancels back
to native color under `.dark` — so contrast tracks the color mode with no JS.
Upgrade the devframe family to 0.9.11 (devtools-kit 0.7.1), which adds the
`allowedOrigins` option to `devframeViteBridge` — the fix for the loopback-only
WS origin check reported upstream (devframes/devframe#348). Drop the inlined
`initDevframe` workaround and go back to the first-class bridge with
`allowedOrigins: false`, restoring the smaller integration.
Dropped during a branch sync; `attw` fails node10 resolution of
`@unocss/inspector/devframe` without it.
@antfu
antfu marked this pull request as ready for review September 4, 2026 02:52
@antfu
antfu added this pull request to the merge queue Sep 4, 2026
Merged via the queue into unocss:main with commit 25973fd Sep 4, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Sponsor
SponsoredKunjungi sekarang
Promo