apps/editor: mount node-registry bootstrap at the root layout
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>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
0bcec8e6ba
commit
c4001a656f
@@ -0,0 +1,16 @@
|
||||
'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
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import { GeistPixelSquare } from 'geist/font/pixel'
|
||||
import { Barlow } from 'next/font/google'
|
||||
import localFont from 'next/font/local'
|
||||
import Script from 'next/script'
|
||||
import { ClientBootstrap } from './client-bootstrap'
|
||||
import './globals.css'
|
||||
|
||||
const geistSans = localFont({
|
||||
@@ -41,7 +42,7 @@ export default function RootLayout({
|
||||
)}
|
||||
</head>
|
||||
<body className="font-sans">
|
||||
{children}
|
||||
<ClientBootstrap>{children}</ClientBootstrap>
|
||||
{process.env.NODE_ENV === 'development' && <Agentation />}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user