feat(core): mirror the dock panel's localStorage state into shared state - #525
feat(core): mirror the dock panel's localStorage state into shared state#525dvcolomban wants to merge 2 commits into
Conversation
`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.
@vitejs/devtools
@vitejs/devtools-kit
@vitejs/devtools-oxc
@vitejs/devtools-rolldown
@vitejs/devtools-vite
@vitejs/devtools-vitest
commit: |
|
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? |
|
Thanks for this fix! As of #529, the client UI previously at Since this PR's changes target code that no longer lives here, we're labeling it |
|
@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 ? |
|
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! |
|
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 |
Why
panelStore(thevite-devtools-dock-statekey) 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
useLocalStoragecall with a small generic helper,useLocalStorageSharedState, that mirrors the whole value intorpc.sharedStateunder 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.open: it's already oneuseLocalStorage-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.
opensees 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.