-
Notifications
You must be signed in to change notification settings - Fork 271
Description
Background
When a server action calls redirect(), the server (in app-rsc-entry.ts) catches the redirect and returns a response with an empty body and an x-action-redirect header. The client currently detects this header and performs a hard navigation (location.assign() / location.replace()) as a workaround.
This is tracked as a known parity gap, introduced in #620 which fixed #589.
What Next.js does
Next.js pre-renders the redirect target's RSC payload as part of the action response body. The client then uses __VINEXT_RSC_NAVIGATE__ (or equivalent) to perform a soft RSC navigation, keeping the existing page shell and only swapping the route content, without a full browser reload.
Current vinext behavior
Full page reload on every server action redirect. This is functionally correct but:
- Causes a flash of unstyled/loading content on redirect
- Loses any in-memory client state not persisted to the URL
- Breaks the expected SPA navigation feel
- Is inconsistent with how
router.push()and link clicks work
What needs to change
In app-rsc-entry.ts (around line 2060), when a server action response catches a NEXT_REDIRECT, the server should:
- Render the redirect target route to an RSC stream
- Send that stream as the response body (instead of an empty body)
- Set
x-action-redirectandx-action-redirect-typeheaders as it does now
The client in app-browser-entry.ts can then remove the hard redirect fallback and resume using __VINEXT_RSC_NAVIGATE__ for all same-origin action redirects.
References
- Fixed by (workaround): fix: prevent useActionState state becoming undefined when redirect() is called (#589) #620
- Original bug report:
useActionStatereceivesundefinedstate when Server Action callsredirect()#589 - Relevant code:
packages/vinext/src/entries/app-rsc-entry.ts~line 2060,packages/vinext/src/server/app-browser-entry.ts~line 144
/cc @yunus25jmi1