mirror of
https://github.com/cloudflare/vinext.git
synced 2026-05-09 08:25:34 +02:00
[GH-ISSUE #50] bug: Invalid hook call + Cannot read properties of null (reading 'useContext') #13
Labels
No labels
enhancement
enhancement
good first issue
help wanted
nextjs-tracking
nextjs-tracking
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/vinext#13
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @XavierGeerinck on GitHub (Feb 25, 2026).
Original GitHub issue: https://github.com/cloudflare/vinext/issues/50
Very nice project! Thanks for making this possible.
I tried migrating, but can't yet as I get the below, any idea?
Analysis
Root cause: React 19 dev-mode crashes in Vinext SSR/RSC outside Next.js
When running
react-server-dom-webpack/client.edgein Vite's SSR environment (via@vitejs/plugin-rsc), two React 19 dev-mode code paths crash becauseReactSharedInternals.H(the hooks dispatcher) isnulloutside a React render cycle:resolveErrorDev— When an RSC stream contains an error, this function builds fake call stacks usingeval'd closures that ultimately callnew Error(). React 19 dev mode interceptsErrorconstruction to capture component stacks, which callsH.useContext→ crashes onnull.useContext.resolveDispatcher— React's ownresolveDispatcher()returnsnullwhenHis unset (outside render), and callers dodispatcher.useContext(Context)→ same null crash. This fires during SSR module loading and RSC stream processing.Next.js avoids this because it always sets up the dispatcher before processing RSC streams. Standalone Vite +
@vitejs/plugin-rscdoes not.Additionally: Package dist files built with
tsdown/tsupoften strip"use client"directives from barrel files. This causes the RSC plugin to treat client components (ThemeProvider, Toaster, auth hooks) as server components, leading to "Functions cannot be passed directly to Client Components" serialization errors.Original Trace
Suggestion
The proper fix should happen at two levels:
1. Vinext/
@vitejs/plugin-rscshould set up the React dispatcher before processing RSC streamsNext.js does this internally — before calling into
react-server-dom-webpack/client.edgeto process RSC streams in SSR, it ensuresReactSharedInternals.His initialized. Vinext's SSR runner should do the same. The fix would be in the SSR entry point that callscreateFromFetch/createFromReadableStream, wrapping it inside a React render context (or manually setting up a minimal dispatcher).2. Vinext should auto-detect missing
"use client"directivesMany packages (next-themes, sonner, better-auth/react) ship dist files without
"use client"because Next.js infers it from the module graph. Vinext could:clientModules: [/next-themes/, /sonner/]that tells the RSC plugin to treat matching modules as client boundariesuseState,useContext, etc.) and auto-mark them as client modules in the RSC environmentinjectClientDirectivesplugin pattern for users to handle this themselves@ryanbuening commented on GitHub (Feb 25, 2026):
I'm possibly seeing a similar issue with NextAuth:
@threepointone commented on GitHub (Feb 26, 2026):
I think we need to solve this in
@vitejs/plugin-rsc@liuxiaopai-ai commented on GitHub (Feb 26, 2026):
Update: a fix is up in PR #118 and now linked as
Fixes #50.https://github.com/cloudflare/vinext/pull/118
@threepointone @southpolesteve could you take a look when you have a moment?
Validation summary (on the PR branch):
pnpm -s run lintpnpm -s run typecheckpnpm -s test tests/app-router.test.tspnpm -s test tests/static-export.test.tspnpm -s test tests/ecosystem.test.tspnpm -s testpassed (47 files / 1820 passed / 3 skipped)