Skip to content

Commit 70d6db2

Browse files
committed
fix(examples): load jsonRenderUiRenderer via bundler-ignored import in hub-next
Turbopack bundled the static `@devframes/json-render-ui/hub` import into the Next server chunk, so the helper's `import.meta.url`-based bundle-path resolution pointed inside `.next/…/assets/dist/` and tripped DF8109. Load it through the same bundler-ignored dynamic `import()` as the plugins, so Node resolves the published `dist` at request time and the renderer module resolves correctly. Also type the React example's dock renderer against the moved `JsonRenderDockRenderer` contract, and widen the client renderer registry's `register`/`renderers` inputs to `DockRenderer<any>` so a renderer narrowed to a specific entry variant plugs in.
1 parent ef831b9 commit 70d6db2

5 files changed

Lines changed: 38 additions & 12 deletions

File tree

examples/hub-next/src/client/devframe/next-devframe-hub.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import type { HubDevframeEntry, HubInstance } from '@devframes/hub/initiate'
1+
import type { DockRendererRegistration, HubDevframeEntry, HubInstance } from '@devframes/hub/initiate'
22
import type { DevframeHubContext } from '@devframes/hub/node'
3+
import type { jsonRenderUiRenderer as JsonRenderUiRenderer } from '@devframes/json-render-ui/hub'
34
import type { DevframeDefinition } from 'devframe'
45
import { homedir } from 'node:os'
56
import process from 'node:process'
67
import { fileURLToPath } from 'node:url'
78
import { defineHubRpcFunction } from '@devframes/hub'
89
import { DEVFRAMES_HUB_BASE, initHub } from '@devframes/hub/initiate'
9-
import { jsonRenderUiRenderer } from '@devframes/json-render-ui/hub'
1010
import { toJsonRenderDockEntry } from '@devframes/json-render/hub'
1111
import { createDashboardView } from 'json-render/dashboard'
1212
import { dirname, join } from 'pathe'
@@ -62,6 +62,19 @@ async function loadAssetsDevframe(): Promise<DevframeDefinition> {
6262
return (mod.createAssetsDevframe as (options: { dir: string, watch: boolean }) => DevframeDefinition)({ dir, watch: false })
6363
}
6464

65+
/**
66+
* The reference json-render renderer registration for `initHub({ renderers })`.
67+
* Loaded through the same bundler-ignored dynamic `import()` as the plugins:
68+
* `jsonRenderUiRenderer()` resolves its prebuilt module via `import.meta.url`,
69+
* which only points at the published `dist` when Node loads the package at
70+
* request time — a static import would be rewritten into a Next server chunk,
71+
* making the path resolve inside `.next/` (see `DF8109`).
72+
*/
73+
async function loadJsonRenderUiRenderer(): Promise<DockRendererRegistration> {
74+
const mod = await import(/* webpackIgnore: true */ /* turbopackIgnore: true */ '@devframes/json-render-ui/hub')
75+
return (mod.jsonRenderUiRenderer as typeof JsonRenderUiRenderer)()
76+
}
77+
6578
/**
6679
* URL base the a11y agent module is served under — inside the hub namespace,
6780
* so the one catch-all route reaches it.
@@ -158,6 +171,10 @@ export async function nextDevframeHub(
158171
// the origin, so their BroadcastChannel connects.
159172
const a11yAgent = await loadA11yAgentMount()
160173

174+
// The reference json-render renderer module, loaded the same bundler-ignored
175+
// way so its `import.meta.url` bundle path resolves to the published `dist`.
176+
const jsonRenderRenderer = await loadJsonRenderUiRenderer()
177+
161178
// Demo devframes alongside the dogfooded built-in plugin packages. The
162179
// shared-iframe soft-navigation demo mounts as a `subTabs` anchor (a shared
163180
// `frameId` + the postmessage protocol) so the client host attaches the
@@ -215,7 +232,7 @@ export async function nextDevframeHub(
215232
// local React renderer for the same type (app/page.tsx), which takes
216233
// precedence — witnessing both sides of the swap seam: the manifest
217234
// composition AND a local frontend replacing it.
218-
renderers: [jsonRenderUiRenderer()],
235+
renderers: [jsonRenderRenderer],
219236
// Record this hub in the global registry so `devframe connect` discovers
220237
// it — running inside the Next dev server — like any standalone devframe.
221238
// The instance owns the record (written once its pinned origin resolves,

examples/hub-next/src/client/json-render/dock-renderer.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,14 +96,18 @@ function JsonRenderView({ spec, rpc, registry, viewId }: JsonRenderViewProps): R
9696
export function createReactJsonRenderDockRenderer(): JsonRenderDockRenderer {
9797
return async ({ entry, container, context }) => {
9898
const view: JsonRenderViewRef = entry.view
99-
const rpc = context.rpc
99+
const { rpc } = context
100+
// The action bridge only needs a loose `call(method, …)` — the client's
101+
// typed `DevframeRpcClient` narrows `method` to known keys, so widen it at
102+
// the prop boundary for the dynamic spec-action names.
103+
const bridgeRpc = rpc as unknown as JsonRenderViewProps['rpc']
100104
const viewId = 'stateKey' in view ? view.stateKey : entry.id
101105
const root = createRoot(container)
102106

103107
// Inline view: render the embedded spec once, no shared state involved.
104108
if ('spec' in view) {
105109
root.render(
106-
<JsonRenderView spec={view.spec} rpc={rpc} registry={baseReactRegistry} viewId={viewId} />,
110+
<JsonRenderView spec={view.spec} rpc={bridgeRpc} registry={baseReactRegistry} viewId={viewId} />,
107111
)
108112
return {
109113
dispose() {
@@ -112,12 +116,12 @@ export function createReactJsonRenderDockRenderer(): JsonRenderDockRenderer {
112116
}
113117
}
114118

115-
const state = await rpc.sharedState.get(view.stateKey, { initialValue: null })
119+
const state = await rpc.sharedState.get<Spec>(view.stateKey, { initialValue: null as unknown as Spec })
116120
const render = (): void => {
117121
root.render(
118122
<JsonRenderView
119123
spec={state.value() as Spec | null}
120-
rpc={rpc}
124+
rpc={bridgeRpc}
121125
registry={baseReactRegistry}
122126
viewId={viewId}
123127
/>,

packages/hub/src/client/host.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ export interface DevframeClientHostOptions {
6666
* Local registrations take precedence over the hub's renderer manifest
6767
* (`initHub({ renderers })`) — explicit local code beats wire config.
6868
*/
69-
renderers?: Record<string, DockRenderer>
69+
renderers?: Record<string, DockRenderer<any>>
7070
/**
7171
* Hub-wide override of the top-level dock-bar category ordering — a map of
7272
* category id → ordering weight (lower sorts earlier), mirroring the shape

packages/hub/src/client/renderers.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,13 @@ export type DockRendererMountResult
6161
* instance and disposes it when the entry deactivates.
6262
*/
6363
export interface DockRenderersContext {
64-
/** Register a renderer for a dock `type`. Returns an unregister function. */
65-
register: (type: string, renderer: DockRenderer) => () => void
64+
/**
65+
* Register a renderer for a dock `type`. Returns an unregister function.
66+
* Accepts a renderer narrowed to any specific entry variant (e.g. a
67+
* {@link DockRenderer}<DevframeJsonRenderDockEntry> from an integration
68+
* package) — the type routes only its own entries to it.
69+
*/
70+
register: (type: string, renderer: DockRenderer<any>) => () => void
6671
/** Look up the locally-registered renderer for a dock `type`, if any. */
6772
get: (type: string) => DockRenderer | undefined
6873
/**
@@ -99,7 +104,7 @@ export interface CreateDockRenderersContextOptions {
99104
/** The assembled client context handed to renderers at mount. */
100105
context: () => DevframeClientContext
101106
/** Renderers registered locally at boot — these win over manifest modules. */
102-
local?: Record<string, DockRenderer>
107+
local?: Record<string, DockRenderer<any>>
103108
/** The current {@link DockRendererManifest} (live getter). */
104109
manifest?: () => DockRendererManifest
105110
/**

packages/json-render-ui/src/.generated/css.ts

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)