mirror of
https://github.com/cloudflare/vinext.git
synced 2026-05-09 08:25:34 +02:00
[PR #910] [MERGED] fix(app-router): action redirects #940
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#940
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?
📋 Pull Request Information
Original PR: https://github.com/cloudflare/vinext/pull/910
Author: @NathanDrake2406
Created: 4/26/2026
Status: ✅ Merged
Merged: 4/27/2026
Merged by: @james-elicx
Base:
main← Head:nathan/app-post-form-actions📝 Commits (5)
3258947Fix app form action redirects22e4f17Trigger CI rerun3f4c5d0Refactor progressive action handlingff42478Address app action review feedback7a263b4Trigger CI rerun📊 Changes
15 files changed (+960 additions, -28 deletions)
View changed files
📝
packages/vinext/src/entries/app-rsc-entry.ts(+32 -3)📝
packages/vinext/src/server/app-route-handler-execution.ts(+17 -6)📝
packages/vinext/src/server/app-route-handler-policy.ts(+22 -1)➕
packages/vinext/src/server/app-server-action-execution.ts(+210 -0)📝
tests/__snapshots__/entry-templates.test.ts.snap(+168 -18)📝
tests/app-route-handler-policy.test.ts(+72 -0)📝
tests/app-router.test.ts(+7 -0)➕
tests/app-server-action-execution.test.ts(+296 -0)📝
tests/e2e/app-router/server-actions.spec.ts(+29 -0)➕
tests/fixtures/app-basic/app/nextjs-compat/action-progressive/page.tsx(+33 -0)➕
tests/fixtures/app-basic/app/nextjs-compat/action-progressive/result/page.tsx(+18 -0)➕
tests/fixtures/app-basic/app/nextjs-compat/api/post-form-permanent-redirect/route.ts(+5 -0)➕
tests/fixtures/app-basic/app/nextjs-compat/api/post-form-redirect/route.ts(+9 -0)➕
tests/fixtures/app-basic/app/nextjs-compat/route-handler-redirects/page.tsx(+7 -0)📝
tests/nextjs-compat/app-routes.test.ts(+35 -0)📄 Description
What changed
decodeAction, and return a real HTTP 303 redirect when the action callsredirect().redirect()andpermanentRedirect()return 303 instead of replay-prone 307/308 semantics.cookies()/ draft-mode cookies when a route handler throws a redirect, matching Next.js app-route behavior.Why
Browser form submissions without JavaScript send
multipart/form-dataand no RSC action header. The previous implementation only handled POSTs withx-rsc-action, so progressive-enhancement server action forms fell through to a normal render and the action was silently skipped.For route handlers,
redirect()encodes 307/308 in the digest, but Next.js overrides action-like POST redirects to 303 so the browser follows with GET instead of resubmitting the original POST.Next.js references
getServerActionRequestMetadata(): marks POSTmultipart/form-data, POSTapplication/x-www-form-urlencoded, and POST action-header requests as possible server actions.action-handler.ts: multipart non-fetch actions calldecodeAction(formData, serverModuleMap)and return through the full-page render path for progressive enhancement.app-route/module.ts: app route redirects returnRedirectStatusCode.SeeOtherwhenactionStore.isActionis true, and append mutable cookies to the redirect response.app-action-progressive-enhancement.test.ts: verifies formData + redirect without JavaScript returns 303 and navigates.app-action.test.ts: verifies POST route-handlerredirect()/permanentRedirect()flows use 303.Validation
vp checkvp test run tests/app-route-handler-policy.test.tsvp test run tests/nextjs-compat/app-routes.test.tsvp test run tests/app-router.test.ts -t "server action"vp test run tests/entry-templates.test.tsvp run vinext#buildPLAYWRIGHT_PROJECT=app-router vp exec playwright test tests/e2e/app-router/server-actions.spec.tsNote: the local pre-commit hook failed in this worktree during Vitest suite initialization before running assertions (
Cannot read properties of undefined (reading 'config')). The same snapshot update/test command passes when run directly throughvp, and the updated snapshot is committed.🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.