fix: add 'use client' to next/dynamic shim for App Router RSC compatibility#7
Merged
southpolesteve merged 1 commit intomainfrom Feb 24, 2026
Merged
Conversation
…bility When a server component imports next/dynamic, the RSC serializer must treat it as a client boundary. Without 'use client', the dynamic() function executes inline in the RSC environment — for ssr:false, this serializes null into the RSC payload and the client never loads the component. Adding 'use client' matches Next.js's App Router behavior where next/dynamic is a client module. The RSC serializer emits a client reference, and the client executes the full dynamic logic including the ssr:false mount-on-client behavior. Updated test fixtures that called dynamic() from server modules to include 'use client' — this is required since dynamic() is now a client export and can only be called from client modules. Added E2E test for ssr:false from a server component page.
|
southpolesteve
added a commit
that referenced
this pull request
Feb 27, 2026
9 Playwright tests covering all middleware behaviors: - Redirect: /old-page → /about with correct URL change - Rewrite: /rewritten serves /ssr content at original URL - Block: /blocked returns 403 with 'Access Denied' body - Header injection: x-middleware-test header on matched pages - Matcher exclusion: /api routes don't get middleware headers - Index page gets middleware headers - Redirect target page is fully functional (client-side nav works) - Rewrite preserves getServerSideProps data and __NEXT_DATA__ - Static file requests not affected by middleware Closes #7
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.
Problem
next/dynamicwithssr: falseproduces a blank page when used from the App Router with the Cloudflare Vite plugin. The dynamically imported component never loads on the client.Root cause
The
shims/dynamic.tsmodule wasn't marked as a client module. When a server component callsdynamic(), the RSC serializer executes the function on the server. Forssr: false, the server path returnsnull, which is serialized into the RSC payload and sent to the client as-is. The client never runs the mount-on-client code path.In Next.js's App Router,
next/dynamicresolves to a"use client"module (app-dynamic.tsx). The RSC serializer emits a client reference instead of executing the function inline.Fix
Added
"use client"to the top ofpackages/vinext/src/shims/dynamic.ts. This makes the dynamic shim a client module, matching Next.js behavior.Both
ssr: trueandssr: falsework correctly:ssr: true— SSR environment resolves the client reference and renders the component to HTML. Client hydrates. No behavior change.ssr: false— SSR rendersnull(viaisServercheck). Client hydrates,useEffectfires → lazy component loads.Test fixture updates
Existing test fixtures that called
dynamic()from server modules now include"use client"— this is required sincedynamic()is a client export. This matches Next.js's App Router behavior where you must calldynamic()from a client module.Added a new E2E test (
ssr:false from server component loads after hydration) with a server component page that imports a client wrapper usingdynamic()withssr: false.All 47 test files pass (1803 tests).