The standalone editor app loaded `lib/bootstrap.ts` as a side-effect
import only from `components/scene-loader.tsx`. That worked for the
`/edit/[sceneId]` route but left every other page (homepage, settings,
viewer-only routes) hitting `<Viewer>` with an empty client-side
registry — node materials resolved to `null` and React surfaced a
`<html>`-level hydration mismatch on first paint.
Fix mirrors the community-app side that landed in pascalorg/private-
editor#27:
- New `app/client-bootstrap.tsx` — thin client wrapper that imports
`../lib/bootstrap` and renders children.
- `app/layout.tsx` mounts `<ClientBootstrap>` around `{children}` so
every page in the standalone editor gets the registry populated
before its first `<Viewer>` / `<Editor>` mounts.
- `lib/bootstrap.ts` switched to **synchronous** built-in registration
via `registerNode(def)` per kind instead of `await loadPlugin(...)`.
The previous async kick-off only resolved in a microtask, letting
the first SSR / hydration pass see an empty registry. External
plugin discovery (`discoverPlugins()`) stays async and runs via its
own `loadExternalPlugins()` path, gated by `externalsKickedOff` so
HMR doesn't re-fetch.
- `components/scene-loader.tsx` drops the per-page side-effect import
— the root provider handles it now.
`bun.lock` syncs `@pascal-app/editor` into `@pascal-app/nodes`'s
peerDependencies + devDependencies (already declared in
`packages/nodes/package.json`; only the lockfile lagged).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
17 lines
698 B
TypeScript
17 lines
698 B
TypeScript
'use client'
|
|
|
|
// Loads `@pascal-app/nodes`' built-in plugin into the node registry on the
|
|
// client. Mounted from `layout.tsx` so every page in the standalone
|
|
// editor gets the registry populated before its first `<Viewer>` /
|
|
// `<Editor>` mounts — without this the registry is empty on the client
|
|
// (the server registers in its own module instance, which is unreachable
|
|
// from hydrated pages) and every `NodeRenderer` resolves to `null`. The
|
|
// `loaded` guard inside `../lib/bootstrap` keeps the side effect
|
|
// idempotent under HMR.
|
|
import '../lib/bootstrap'
|
|
import type { ReactNode } from 'react'
|
|
|
|
export function ClientBootstrap({ children }: { children: ReactNode }) {
|
|
return children
|
|
}
|