Skip to content

apps/nextjs playground + SSR fix (2.0.0-next.2)#79

Merged
desko27 merged 3 commits into
mainfrom
apps/nextjs-playground
May 23, 2026
Merged

apps/nextjs playground + SSR fix (2.0.0-next.2)#79
desko27 merged 3 commits into
mainfrom
apps/nextjs-playground

Conversation

@desko27
Copy link
Copy Markdown
Owner

@desko27 desko27 commented May 23, 2026

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) — getServerSnapshot returned 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 at apps/nextjs/ as the verification rig.

  • Workspace plumbing:

    • `pnpm-workspace.yaml`: `sharp: false` (Next 15 pulls it for Image optimisation; 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`.

What this triggers

  • ci.yml runs on this PR.
  • After merge: release.yml opens a Version Packages PR bumping to 2.0.0-next.2. Merging that publishes to npm under `next` dist-tag.

desko27 added 3 commits May 23, 2026 05:48
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.
@vercel
Copy link
Copy Markdown

vercel Bot commented May 23, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
react-call Ready Ready Preview, Comment May 23, 2026 3:54am

@desko27 desko27 merged commit 6b6ecb3 into main May 23, 2026
8 checks passed
@desko27 desko27 deleted the apps/nextjs-playground branch May 23, 2026 03:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant