diff --git a/packages/vinext/src/server/app-dev-server.ts b/packages/vinext/src/server/app-dev-server.ts index 8ea2eac5..5acb2557 100644 --- a/packages/vinext/src/server/app-dev-server.ts +++ b/packages/vinext/src/server/app-dev-server.ts @@ -2296,6 +2296,7 @@ import { setNavigationContext, ServerInsertedHTMLContext } from "next/navigation import { runWithNavigationContext as _runWithNavCtx } from "vinext/navigation-state"; import { safeJsonStringify } from "vinext/html"; import { createElement as _ssrCE } from "react"; +import * as _clientRefs from "virtual:vite-rsc/client-references"; /** * Collect all chunks from a ReadableStream into an array of text strings. @@ -2420,6 +2421,21 @@ function createRscEmbedTransform(embedStream) { * and the data needs to be passed to SSR since they're separate module instances. */ export async function handleSsr(rscStream, navContext, fontData) { + // Eagerly preload all client reference modules before SSR rendering. + // On the first request after server start, client component modules are + // loaded lazily via async import(). Without this preload, React's + // renderToReadableStream rejects because the shell can't resolve client + // components synchronously (there is no Suspense boundary wrapping the + // root). The memoized require cache ensures this is only async on the + // very first call; subsequent requests resolve from cache immediately. + if (_clientRefs?.default && globalThis.__vite_rsc_client_require__) { + await Promise.all( + Object.keys(_clientRefs.default).map((id) => + globalThis.__vite_rsc_client_require__(id).catch?.(() => {}) + ) + ); + } + // Wrap in a navigation ALS scope for per-request isolation in the SSR // environment. The SSR environment has separate module instances from RSC, // so it needs its own ALS scope.