Skip to content

feat(core): mirror the dock panel's localStorage state into shared state - #525

Closed
dvcolomban wants to merge 2 commits into
vitejs:mainfrom
dvcolomban:dvcol/dock-panel-shared-state
Closed

feat(core): mirror the dock panel's localStorage state into shared state#525
dvcolomban wants to merge 2 commits into
vitejs:mainfrom
dvcolomban:dvcol/dock-panel-shared-state

Conversation

@dvcolomban

@dvcolomban dvcolomban commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Why

panelStore (the vite-devtools-dock-state key) is purely browser-local today — nothing on the Node/server side can see it, including whether the panel is even open. Any Node-side plugin that wants to react to dock UI state — gate some behavior on visibility, log usage, sync it elsewhere — has nothing to observe.

What changed

  • Wraps the existing useLocalStorage call with a small generic helper, useLocalStorageSharedState, that mirrors the whole value into rpc.sharedState under the same key. Shared-state mutations already round-trip through the server before reappearing locally, so that's the entire mechanism — no new dock-entry field, no client-script gating, no RPC command, no trust handshake.
  • Mirrors the whole object rather than cherry-picking open: it's already one useLocalStorage-backed, fully serializable, browser-local singleton (not per-tab), so a second, narrower key for just one field would just be a redundant place for that field to live.

Known limitation, flagging it rather than hiding it: shared state is one authoritative value, last-mutation-wins — with two tabs open, a Node-side consumer watching e.g. open sees whichever tab mutated most recently. Per-connection keying would need a way to garbage-collect a disconnected tab's entry, and nothing in the public API exposes that today, so I went with the simpler singleton.

Linked Issues

Additional context

Verified with pnpm build, pnpm test (5 new tests for the helper, 384 passing total), pnpm typecheck, pnpm lint — all green.

`panelStore` (`vite-devtools-dock-state`) is purely browser-local
today — a node-side plugin has no way to observe it, including whether
the panel is even open. Wrap the existing `useLocalStorage` call with
a small generic helper, `useLocalStorageSharedState`, that mirrors the
whole value into `rpc.sharedState` under the same key: shared-state
mutations already round-trip through the server before reappearing
locally, so this is the entire mechanism — no new dock-entry field, no
client-script gating, no RPC command, no trust handshake.

Deliberately mirrors the whole object rather than cherry-picking
`open`: it's already one `useLocalStorage`-backed, fully serializable,
browser-local singleton (not per-tab) — a second, narrower key for one
of its fields would just be a redundant place for that field to live.

Known, accepted limitation: shared state is one authoritative value,
last-mutation-wins, so a node-side consumer watching `open` across two
open tabs sees whichever one mutated most recently. Per-connection
keying would need a way to garbage-collect a disconnected tab's entry,
which nothing in the public API exposes today — revisit if that changes.
@pkg-pr-new

pkg-pr-new Bot commented Aug 10, 2026

Copy link
Copy Markdown

Open in StackBlitz

@vitejs/devtools

npm i https://pkg.pr.new/@vitejs/devtools@525

@vitejs/devtools-kit

npm i https://pkg.pr.new/@vitejs/devtools-kit@525

@vitejs/devtools-oxc

npm i https://pkg.pr.new/@vitejs/devtools-oxc@525

@vitejs/devtools-rolldown

npm i https://pkg.pr.new/@vitejs/devtools-rolldown@525

@vitejs/devtools-vite

npm i https://pkg.pr.new/@vitejs/devtools-vite@525

@vitejs/devtools-vitest

npm i https://pkg.pr.new/@vitejs/devtools-vitest@525

commit: db5b086

@dvcolomban
dvcolomban marked this pull request as ready for review August 10, 2026 15:17
@antfu

antfu commented Aug 14, 2026

Copy link
Copy Markdown
Member

I am not sure why you need such data synced to the server. To me this should be a pure client-side state, and should not be interfered across clients/devices. Could you explain more?

@antfubot

Copy link
Copy Markdown
Collaborator

Thanks for this fix!

As of #529, the client UI previously at packages/core/src/client/** (webcomponents, dock, floating popover, json-render, inject runtime, etc.) has moved out of this repo. It now lives upstream in devframe (@devframes/hub-ui / @devframes/json-render-ui), and this repo consumes it as a published dependency instead of owning the source.

Since this PR's changes target code that no longer lives here, we're labeling it devframe. We've opened devframes/devframe#211 to port this fix upstream and credit you as the original author — thank you for the work, and sorry for the churn from the migration. Feel free to pick up the port yourself against devframe (linking back to this PR) if you'd like; otherwise we'll route it through the linked issue.

@antfubot antfubot added the devframe Affected by the devframe/hub-ui migration; fix belongs upstream in devframe label Aug 14, 2026
@dvcolomban

Copy link
Copy Markdown
Contributor Author

@antfu We're implementing a devtool UI that inject overrides & code snippet into the live page (and require a hard page reload, not HMR), to avoid unnecessary page reload while the user is interacting with the dock we want a way to detect if the panel is active, and it's current state.

Then when panel close or is collapsed, we can fire state commits & page reload. Without a way to subscribe/listen to the panel state, we have to inject with clientScript some visibility hooks that listen to dock exit.

And even this is partial because it can detect a dock going inactive, but not the full panel (if the user move to other dock, not owned by our tooling, like plugins).

But maybe I missed an easier way to listen to global panel state / events server side ?

ps: should we continue this thread over on the devframe issue instead ?

@antfu

antfu commented Aug 14, 2026

Copy link
Copy Markdown
Member

Hey @dvcolomban, thanks for the contributions and I am glad to hear you are building something on top of Vite DevTools, your feedback is definitely very valuable, and I would love to do my best to make your use case possible/eaiser. I am sorry for the mess on the refactoring (we want to make the DevTools have an even wider ecosystem not just Vite, that's the reason we are extracting things to devframe to make them more agnostic and flexible).

That said, could you create a new issue in devframe repo to explain what you expect (together with #527) for Vite DevTools/Devframe to provide and we can discuss and find a good solution together?

I am also hesitant about #527 as well, as they seem also related to what you are trying to achieve, could you also include that part?

Thanks a lot!

@dvcolomban

Copy link
Copy Markdown
Contributor Author

Closing in favor of a consolidated issue on devframe, per the discussion above — filed both the need and the two problems (panel-exit signal, UI state across reload) together rather than as two separate PRs to port: devframes/devframe#229

@dvcolomban dvcolomban closed this Aug 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

devframe Affected by the devframe/hub-ui migration; fix belongs upstream in devframe

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants