apps/nextjs playground + SSR fix (2.0.0-next.2)#79
Merged
Conversation
React's useSyncExternalStore compares snapshots with Object.is. Our `getServerSnapshot: () => []` returned a fresh array each call, so the comparison always reported "changed" and React 18+ logged "The result of getServerSnapshot should be cached to avoid an infinite loop" on every render under SSR. Stash a single stable empty stack at module scope and return that. On the server the stack is always empty (no call() can run before hydration), and hydration switches the hook to getSnapshot — the shared reference is safe. Surfaced by apps/nextjs playground; the Vite CSR playground never hit the SSR code path. Shipped briefly in 2.0.0-next.1; needs a 2.0.0-next.2 to release the fix. Regression test in ssr.test.tsx asserts Object.is stability directly against `createStackStore` since vitest's happy-dom environment does not surface React's runtime warning the way a real browser does.
Minimal Next.js 15 App Router app that reproduces the exact shape of issue #39: layout.tsx is an `async` Server Component that mounts the Callable imported from a `'use client'` module. Used as a regression rig for the ADR-0009 + ADR-0013 hypothesis that the bare-component form `<Confirm />` fixes the RSC error the original `<Confirm.Root />` shape produced. Verified manually via Claude Preview: - `<Confirm />` (current committed state): page renders clean, no console errors, dialog opens via .call() from a client-side button, end()-ing the dialog dismisses it. End-to-end works. - `<Confirm.Root />` (swapped in temporarily): React throws "Element type is invalid... got: undefined. Check the render method of `RootLayout`." Same root cause as #39 (the Next 14 era message was "Unsupported Server Component type: undefined"; Next 15 rephrased it). The property access on the client reference resolves to undefined. Conclusion: ADR-0013's deprecation of `Callable.Root` in favour of the bare form effectively closes #39 for users on the recommended pattern. The destructuring workaround documented in the README's "Next.js / RSC" section is no longer necessary in 2.0. Workspace plumbing: - pnpm-workspace.yaml: sharp set to `false` (Next 15 pulls it for Image optimization; not used by the playground). - .claude/launch.json: nextjs-playground entry on port 3001. - biome.json: override that disables noDefaultExport for Next App Router files where the framework mandates `export default` (page, layout, template, loading, error, not-found, default, route).
- Changeset (patch) describing the getServerSnapshot fix landed in e8b8b2e. Drives CI's Version PR to bump to 2.0.0-next.2 once the apps/nextjs-playground PR merges to main. - README "Next.js / RSC" section rewritten: the destructuring workaround documented for the 1.x era is no longer needed in 2.0 (ADR-0009 made the Callable a function, ADR-0013 deprecated `.Root`). New section just covers the `'use client'` directive and points at apps/nextjs as the verification rig.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to PR #76 / the 2.0.0-next.1 cut. Adds a Next.js / RSC playground that verifies issue #39 is closed by the bare-component form, and ships the SSR fix that the playground surfaced.
What's here
apps/nextjs/— minimal Next.js 15 App Router app mirroring the exact shape of issue bug: layout.tsx - Error: Unsupported Server Component type: undefined #39 (async Server Component layout.tsx mounting the Callable from a'use client'module). Verified end-to-end via Claude Preview:<Confirm />(the canonical 2.0 form per ADR-0013): page renders clean, dialog opens via .call() from a client-side button. End-to-end works.<Confirm.Root />(the deprecated alias, swapped in temporarily): React 'Element type is invalid... got: undefined. Check the render method of `RootLayout`.' Same root cause as bug: layout.tsx - Error: Unsupported Server Component type: undefined #39.SSR fix in createStackStore (e8b8b2e) —
getServerSnapshotreturned a fresh[]each call. React 18+ flagged it as 'The result of getServerSnapshot should be cached to avoid an infinite loop' on every render under SSR. The bug shipped briefly in 2.0.0-next.1; the playground surfaced it (Vite CSR never hit the SSR path). Fix is a stable module-level empty reference + regression test in ssr.test.tsx.Changeset (patch) — drives the next Version PR to bump to 2.0.0-next.2 with the SSR fix as the changelog entry.
README 'Next.js / RSC' section rewritten — the destructuring workaround from the 1.x era is no longer needed. New section just covers the
'use client'directive + points atapps/nextjs/as the verification rig.Workspace plumbing:
What this triggers