Nuxt
@devframes/nuxt splits into @devframes/nuxt/single (author one devframe) and @devframes/nuxt/hub (mount a hub); the bare import throws.
The single module wires a Nuxt SPA as a devframe's browser side and types useNuxtApp().$rpc as DevframeRpcClient.
Install
export default defineNuxtConfig({
modules: ['@devframes/nuxt/single'],
})Using $rpc
<script setup>
const { $rpc } = useNuxtApp()
const payload = await $rpc.call('my-tool:get-payload')
</script>Or a composable:
export function usePayload() {
const { $rpc } = useNuxtApp()
return useAsyncData('payload', () => $rpc.call('my-tool:get-payload'))
}Options
export default defineNuxtConfig({
modules: ['@devframes/nuxt/single'],
devframe: {
baseURL: './', // where the devframe snapshot lives, relative to the page
skipAppDefaults: false, // opt out of the app.baseURL / vite.base defaults
},
})baseURLresolves againstdocument.baseURIat runtime.skipAppDefaults: trueships absolute asset paths.
Dev-time RPC bridge
Pass a devframe definition:
import myDevframe from './src/my-tool' // defineDevframe(...) export
export default defineNuxtConfig({
modules: [['@devframes/nuxt/single', { devframe: myDevframe }]],
})nuxt dev now:
- Starts a WebSocket RPC server on a
get-port-pleaseport (respectsdevframe.cli.port/portRange/random). - Registers Vite middleware at
${baseURL}__connection.json. - Runs
devframe.setup(ctx, { flags }). - Cleans up on Vite restart,
nuxt devshutdown, and bundle close.
On by default when devframe is set; disable it (browser side only) with devMiddleware: false.
Customizing the bridge
export default defineNuxtConfig({
modules: [['@devframes/nuxt/single', {
devframe: myDevframe,
devMiddleware: {
port: 7777,
host: '0.0.0.0',
flags: { config: process.env.MY_CONFIG },
},
}]],
})portpins the bridge port (elseget-port-pleasepicks one).hostdefaults tonuxt.options.devServer.host ?? devframe.cli?.host ?? 'localhost'.flags→devframe.setup(ctx, { flags }).
Relationship to createCac
Production uses createCac (or createBuild), producing a static __connection.json + __rpc-dump/ snapshot from clientAssets:
my-tool/
├── bin.mjs # createCac(myDevframe).parse()
├── src/
│ ├── my-tool.ts # defineDevframe + setup(ctx) { ctx.rpc.register(...) }
│ └── app/ # Nuxt SPA, uses `@devframes/nuxt`
└── dist/
├── cli.mjs # bundled Node entry
└── public/ # Nuxt build output, pointed at by clientAssetsHow it works
At build time it sets the app.baseURL / vite.base defaults, merges { devframe: { baseURL } } into runtimeConfig.public, and injects a client-only plugin (helpers/nuxt/runtime/plugin.client):
const rpc = await connectDevframe({ baseURL: config.public.devframe.baseURL })
return { provide: { rpc } }At runtime the SPA fetches ./__connection.json and branches on backend: websocket in dev, static from a createBuild snapshot.
Mounting a hub
@devframes/nuxt/hub mounts a whole hub alongside nuxt dev, injecting @devframes/hub-ui's dock. ui swaps the default; ui: false gives a headless hub via @devframes/nuxt/hub/client.
export default defineNuxtConfig({
modules: [['@devframes/nuxt/hub', { devframes: [] }]],
})Nuxt DevTools (@nuxt/devtools) integrates the same protocol natively; this module recommends it once (silence with { quiet: true }).
See also
- Standalone CLI recipe
- Client:
connectDevframereference - Adapters
Vite
@devframes/vite splits into @devframes/vite/single (dev-serve one devframe's SPA) and @devframes/vite/hub (mount a hub); the bare import throws.
Next
@devframes/next hosts devframes from a Next.js App Router app via a route handler: one fetch handler serves each SPA and its __connection.json via serveStaticHandler.