feat(hub): resolve bare-specifier client scripts through the host runtime - #257
Merged
Conversation
…time
A dock client script's importFrom can now name an npm module (e.g.
'vite-plugin-vue-tracer/client/vite-devtools') instead of a served URL.
Bare specifiers are a host-runtime capability: the host advertises a URL
template as ConnectionMeta.configs.dock.clientModuleResolution (declared
via initHub({ clientModuleResolution })), and every client-script loader
applies it before the native import — createDevframeClientHost (which
also gains a resolveClientModule override), hub-ui's setup-script
loader, and the generated __client-imports.js module.
@devframes/vite/hub declares '/@id/{specifier}' by default, so the
import routes through Vite's own resolution and import-analysis: the
script's transitive bare imports work too and share the app's module
graph — the fix for vue-tracer's dock breaking once v0.9's middleware
began serving hub assets verbatim, outside Vite's transform pipeline.
Hosts without such a runtime (Next.js) keep the URL contract; a new
DF8111 diagnostic warns at dock registration when a bare specifier is
doomed there, and both browser loaders name the capability gap in their
error. The reference hubs stay at parity through one shared demo
package (examples/demo-dock-client): hub-vite consumes it by bare
specifier, hub-next as a statically-mounted self-contained bundle, and
its globalThis-anchored store documents the state pattern the docs'
new protocol guarantee prescribes.
✅ Deploy Preview for devfra ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
…ved-but-unservable client scripts The hub-vite demo failed with 'Failed to fetch dynamically imported module' whenever demo-dock-client's dist was absent (running vite without the repo build): Vite couldn't resolve the /@id/ request's exports target and the SPA index.html fallback answered 200 with HTML. The package's '.' export now points at src/index.ts — a Vite host transforms the linked source directly, so the bare-specifier path needs no build at all; tsdown keeps building only the URL-shape artifacts (dist/bundle.mjs + dist/node.mjs for the Next host). Both browser loaders also gain a second diagnosis branch via the shared clientScriptFailureHint(): when a bare specifier WAS resolved through the host template and the import still failed, the error now points at the module being unservable on the host (package not installed/built) instead of leaving only the browser's opaque TypeError.
Public API narrows to what consumers actually touch: the initHub clientModuleResolution option, the createDevframeClientHost resolveClientModule override, and — on @devframes/hub/client, for viewers and hub-ui — resolveClientModuleSpecifier + clientScriptFailureHint. The template token constant, the standalone template applier, the options interface, the DockConnectionConfig type (now inlined in the configs augmentation), and @devframes/vite/hub's clientModuleResolution option + exported constant all fold away; the resolver takes the template directly, so the node-side imports-module rendering reuses it instead of its own helper pair.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Since the v0.9 init/middleware refactor, every hub asset is served verbatim by devframe's own middleware, ahead of Vite's transform pipeline — so a dock client script declared with a bare npm specifier (
vite-plugin-vue-tracer'saction: { importFrom: 'vite-plugin-vue-tracer/client/vite-devtools' }) reaches the browser's nativeimport()unresolved and throwsTypeError: Failed to resolve module specifier.Model: bare specifiers are a host-runtime capability
The hub protocol gains the hook; hosts whose runtime can serve resolvable module URLs declare it; the hub core ships no module serving of its own.
ConnectionMeta.configs.dock.clientModuleResolution— a host-declared URL template ({specifier}token), published viainitHub({ clientModuleResolution })and applied by every client-script loader:createDevframeClientHost, hub-ui's setup-script loader, and the generated__client-imports.jsmodule.createDevframeClientHost({ resolveClientModule })— a viewer-side override that wins over the meta template (how a custom viewer like Vite DevTools can opt in without the meta field).@devframes/vite/hubdeclares'/@id/{specifier}'by default — the import routes through Vite's own resolution and import-analysis, so the script's transitive bare imports work too and share the inspected app's module graph (vue-tracer needs zero changes).DF8111diagnostic warns at dock registration when a bare specifier can't resolve there, and both browser loaders name the capability gap in their error instead of surfacing the browser's opaque TypeError.Docs
docs/guide/client-context.md— the twoimportFromshapes, plus the protocol guarantee: client scripts execute in the inspected page's realm; module identity is best-effort (Vite) — plugins with shared state should anchor it onglobalThis, vue-tracer's__vue_tracer__store being the reference pattern.docs/errors/DF8111.md.Example parity
One shared demo package (
examples/demo-dock-client, nanoevents dep +globalThis-anchored store) consumed in both shapes: hub-vite by bare specifier through/@id/, hub-next as a statically-mounted self-contained bundle — both READMEs state the capability difference explicitly. Both reference clients also learn to renderactiondocks as momentary rail buttons.Verification
client-modules.test.ts), the meta advertisement +__client-imports.jsrewriting (initiate.test.ts), andDF8111(host-docks.test.ts); tsnapi API snapshots updated./@id/demo-dock-clientserved Vite-transformed JS with its barenanoeventsimport rewritten into the module graph, and clicking the dock produced the demo script's activation message end to end.Follow-up (separate repo):
@vitejs/devtools-kitpasses the resolver / declares the meta field — one-line adoption.Created with the help of an agent.