You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
buildHub (@devframes/hub/build, #339) bakes a whole static hub — but it owns the entire pipeline: it creates its own createHubContext({ mode: 'build' }), mounts devframes from a devframes/configure input, then does the baking (static-dir copy, renderer manifest, UI artifacts, __client-imports.js, __index.json, hub + per-frame __connection.json, and the RPC dump).
Vite DevTools (@vitejs/devtools + @vitejs/devtools-kit) can't feed it that way, so today it re-implements the whole baker by hand (packages/core/src/node/build-static.ts) and drifts out of sync with upstream — e.g. the 0.9.10 collectStaticRpcDump format change (files became { serialization, fnName, data } wrappers with per-file structured-clone/json encoding) silently broke our hand-rolled JSON.stringify(data) writer until we switched to the now-shared writeStaticRpcDump.
We'd like to reuse buildHub's baking instead of shadowing it. A few things block that.
Why buildHub's own-context model doesn't fit
Vite DevTools assembles its context differently from a plain hub:
Kit-augmented context. It builds via createKitContext (wraps createHubContext) so the context carries Vite-specific slots (viteConfig/viteServer) that the integrations' setup(ctx) hooks read. buildHub's internal createHubContext(...) produces a plain hub context without them.
Devframes arrive as Vite plugins, not a devframes array. Built-ins and user integrations are mounted by scanning viteConfig.plugins for a .devtools.setup hook and running it against the context — arbitrary Vite plugins, not DevframeDefinitions we can enumerate into buildHub({ devframes }).
Capability gating happens Vite-side (shouldSkipSetupByCapabilities on plugin.devtools.capabilities[mode]), before mount.
So we need to create + mount the context ourselves and hand the already-mounted context to the baker.
Requests (roughly in priority order)
Expose the post-mount baker as a public function that takes an existing, already-mounted DevframeHubContext. Something like bakeHubStatic(ctx, { outDir, base, ui, renderers, name, version, pretty }) that runs exactly the tail of buildHub (renderer manifest → UI artifacts → __client-imports.js → __index.json → hub + per-frame __connection.json → collectStaticRpcDump + writeStaticRpcDump), without creating a context or mounting devframes. buildHub then becomes createHubContext + mountDevframes + bakeHubStatic(ctx, opts). This single change unblocks us — we stop shadowing the whole file and inherit format/behaviour fixes for free.
Frame discovery from an externally-mounted context. The baker needs the installed frames + their bases to write __index.json and per-frame __connection.json. In buildHub these come from mountDevframes' return value and host.mountConnectionMeta. For a context mounted by the caller, please expose a public way to enumerate mounted frames/bases (e.g. ctx.frames, or via getInternalContext) so the baker can emit the index + per-frame metas it did not mount itself. (Today our hand-rolled builder writes only a single hub __connection.json and no __index.json, so a frame SPA loaded standalone can't find the shared dump — the exact gap feat(hub): static hub builds with buildHub #339 fixed for buildHub.)
Materialize views.buildStaticDirs from the provided context. In build mode the kit host's mountStatic is a no-op ("baked into build output by createBuild"), so statics registered via views.hostStatic are only reachable through ctx.views.buildStaticDirs (each { baseUrl, source }, some remote-asset sources needing resolveStaticAssetsSource(...).materialize(dir)). buildHub copies statics as a side effect of its own H3 host's mount during mounting; the extracted baker should instead iterate the provided context's views.buildStaticDirs so an externally-mounted context's statics get copied.
Don't unconditionally rm -rfoutDir.buildHub does if (existsSync(outDir)) await fs.rm(outDir, { recursive: true }). When baking into an existing app build output (the @devframes/vite/hubbuild: true case, and our build.withApp), the devtools subtree lives alongside the app's own dist/. A clean?: boolean opt-out (default keeping today's behaviour) would make it safe to point the baker at a shared directory.
Alternative (smaller scope)
If extracting a public baker is too big, publishing the internal helpers buildHub composes — mountDevframes, renderClientImportsModule, resolveRendererRegistrations, and the __index.json / connection-meta writers (currently private in the assemble chunk; only createHubContext and buildHub are public from @devframes/hub/node and @devframes/hub/build) — would at least let downstreams compose their own baker without copy-pasting upstream. The extracted bakeHubStatic(ctx, opts) is the cleaner outcome, though.
What
buildHub(@devframes/hub/build, #339) bakes a whole static hub — but it owns the entire pipeline: it creates its owncreateHubContext({ mode: 'build' }), mounts devframes from adevframes/configureinput, then does the baking (static-dir copy, renderer manifest, UI artifacts,__client-imports.js,__index.json, hub + per-frame__connection.json, and the RPC dump).Vite DevTools (
@vitejs/devtools+@vitejs/devtools-kit) can't feed it that way, so today it re-implements the whole baker by hand (packages/core/src/node/build-static.ts) and drifts out of sync with upstream — e.g. the 0.9.10collectStaticRpcDumpformat change (files became{ serialization, fnName, data }wrappers with per-file structured-clone/json encoding) silently broke our hand-rolledJSON.stringify(data)writer until we switched to the now-sharedwriteStaticRpcDump.We'd like to reuse
buildHub's baking instead of shadowing it. A few things block that.Why
buildHub's own-context model doesn't fitVite DevTools assembles its context differently from a plain hub:
createKitContext(wrapscreateHubContext) so the context carries Vite-specific slots (viteConfig/viteServer) that the integrations'setup(ctx)hooks read.buildHub's internalcreateHubContext(...)produces a plain hub context without them.devframesarray. Built-ins and user integrations are mounted by scanningviteConfig.pluginsfor a.devtools.setuphook and running it against the context — arbitrary Vite plugins, notDevframeDefinitions we can enumerate intobuildHub({ devframes }).shouldSkipSetupByCapabilitiesonplugin.devtools.capabilities[mode]), before mount.So we need to create + mount the context ourselves and hand the already-mounted context to the baker.
Requests (roughly in priority order)
Expose the post-mount baker as a public function that takes an existing, already-mounted
DevframeHubContext. Something likebakeHubStatic(ctx, { outDir, base, ui, renderers, name, version, pretty })that runs exactly the tail ofbuildHub(renderer manifest → UI artifacts →__client-imports.js→__index.json→ hub + per-frame__connection.json→collectStaticRpcDump+writeStaticRpcDump), without creating a context or mounting devframes.buildHubthen becomescreateHubContext+mountDevframes+bakeHubStatic(ctx, opts). This single change unblocks us — we stop shadowing the whole file and inherit format/behaviour fixes for free.Frame discovery from an externally-mounted context. The baker needs the installed frames + their bases to write
__index.jsonand per-frame__connection.json. InbuildHubthese come frommountDevframes' return value andhost.mountConnectionMeta. For a context mounted by the caller, please expose a public way to enumerate mounted frames/bases (e.g.ctx.frames, or viagetInternalContext) so the baker can emit the index + per-frame metas it did not mount itself. (Today our hand-rolled builder writes only a single hub__connection.jsonand no__index.json, so a frame SPA loaded standalone can't find the shared dump — the exact gap feat(hub): static hub builds with buildHub #339 fixed forbuildHub.)Materialize
views.buildStaticDirsfrom the provided context. In build mode the kit host'smountStaticis a no-op ("baked into build output by createBuild"), so statics registered viaviews.hostStaticare only reachable throughctx.views.buildStaticDirs(each{ baseUrl, source }, some remote-asset sources needingresolveStaticAssetsSource(...).materialize(dir)).buildHubcopies statics as a side effect of its own H3 host'smountduring mounting; the extracted baker should instead iterate the provided context'sviews.buildStaticDirsso an externally-mounted context's statics get copied.Don't unconditionally
rm -rfoutDir.buildHubdoesif (existsSync(outDir)) await fs.rm(outDir, { recursive: true }). When baking into an existing app build output (the@devframes/vite/hubbuild: truecase, and ourbuild.withApp), the devtools subtree lives alongside the app's owndist/. Aclean?: booleanopt-out (default keeping today's behaviour) would make it safe to point the baker at a shared directory.Alternative (smaller scope)
If extracting a public baker is too big, publishing the internal helpers
buildHubcomposes —mountDevframes,renderClientImportsModule,resolveRendererRegistrations, and the__index.json/ connection-meta writers (currently private in theassemblechunk; onlycreateHubContextandbuildHubare public from@devframes/hub/nodeand@devframes/hub/build) — would at least let downstreams compose their own baker without copy-pasting upstream. The extractedbakeHubStatic(ctx, opts)is the cleaner outcome, though.Context
buildHub:packages/hub/src/node/build.ts(from feat(hub): static hub builds with buildHub #339)vitejs/devtoolspackages/core/src/node/build-static.tsCreated with the help of an agent.