[PR #854] [MERGED] Preserve intercepted app-router state across server actions #898

Closed
opened 2026-05-06 13:10:43 +02:00 by BreizhHardware · 0 comments

📋 Pull Request Information

Original PR: https://github.com/cloudflare/vinext/pull/854
Author: @NathanDrake2406
Created: 4/16/2026
Status: Merged
Merged: 4/20/2026
Merged by: @james-elicx

Base: mainHead: interception-context


📝 Commits (4)

  • 00f14d6 Preserve interception context on app-router actions
  • d8da98b Keep intercept slot overrides on action rerenders
  • eac991a Pin React versions in static-export fixture
  • 653436c refactor(app-page-request): unify intercept resolution into a single state machine

📊 Changes

14 files changed (+916 additions, -63 deletions)

View changed files

📝 packages/vinext/src/entries/app-rsc-entry.ts (+36 -5)
📝 packages/vinext/src/server/app-browser-entry.ts (+15 -4)
📝 packages/vinext/src/server/app-browser-state.ts (+52 -1)
📝 packages/vinext/src/server/app-page-request.ts (+154 -17)
📝 pnpm-lock.yaml (+2 -2)
📝 tests/__snapshots__/entry-templates.test.ts.snap (+216 -30)
📝 tests/app-browser-entry.test.ts (+83 -0)
📝 tests/app-page-request.test.ts (+264 -0)
📝 tests/e2e/app-router/advanced.spec.ts (+39 -0)
📝 tests/entry-templates.test.ts (+10 -1)
tests/fixtures/app-basic/app/feed/@modal/(...)photos/[id]/actions.ts (+13 -0)
tests/fixtures/app-basic/app/feed/@modal/(...)photos/[id]/like-button.tsx (+24 -0)
📝 tests/fixtures/app-basic/app/feed/@modal/(...)photos/[id]/page.tsx (+6 -1)
📝 tests/fixtures/static-export/package.json (+2 -2)

📄 Description

Summary

  • send interception context and mounted slot headers on app-router server action POSTs using the current browser router state
  • reuse a shared action rerender target helper so POST rerenders preserve both intercepted source-route trees and current-route slot overrides
  • add regression coverage for the browser-state helper, generated RSC entry code, and the intercepted modal server-action flow
  • pin react and react-dom versions in the static-export fixture to match the resolved lockfile state

Examples

  • Before: open /feed, soft-navigate to /photos/42, then trigger a server action from the modal. The POST omitted interception provenance, so the rerender could replace the modal tree with the direct /photos/[id] page.
    After: the same action keeps the modal mounted, keeps the feed layout visible, and leaves the URL at /photos/42.
  • Before: when an intercept resolved back to the current route, the GET path still preserved interceptOpts for slot overrides, but the POST rerender path dropped them.
    After: both GET and POST use the same rerender-target selection logic, so current-route interception shapes keep their slot overrides.
  • static-export fixture dependencies now declare react and react-dom as ^19.2.5 instead of catalog: so the fixture package manifest matches the checked-in lockfile state.

Testing

  • vp test run tests/app-browser-entry.test.ts tests/app-page-request.test.ts tests/entry-templates.test.ts
  • PLAYWRIGHT_PROJECT=app-router vp run test:e2e tests/e2e/app-router/advanced.spec.ts -g 'server action from intercepted modal preserves modal tree'

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/cloudflare/vinext/pull/854 **Author:** [@NathanDrake2406](https://github.com/NathanDrake2406) **Created:** 4/16/2026 **Status:** ✅ Merged **Merged:** 4/20/2026 **Merged by:** [@james-elicx](https://github.com/james-elicx) **Base:** `main` ← **Head:** `interception-context` --- ### 📝 Commits (4) - [`00f14d6`](https://github.com/cloudflare/vinext/commit/00f14d6b4a204f02ba92ae813ad18056db38d31d) Preserve interception context on app-router actions - [`d8da98b`](https://github.com/cloudflare/vinext/commit/d8da98be674f4218430020c0fb9761e747cd8c16) Keep intercept slot overrides on action rerenders - [`eac991a`](https://github.com/cloudflare/vinext/commit/eac991a675d0e11e6ea3f1e14d3d37a795cbcb85) Pin React versions in static-export fixture - [`653436c`](https://github.com/cloudflare/vinext/commit/653436c9070cc5caa9411a7fbbf9d80dec111485) refactor(app-page-request): unify intercept resolution into a single state machine ### 📊 Changes **14 files changed** (+916 additions, -63 deletions) <details> <summary>View changed files</summary> 📝 `packages/vinext/src/entries/app-rsc-entry.ts` (+36 -5) 📝 `packages/vinext/src/server/app-browser-entry.ts` (+15 -4) 📝 `packages/vinext/src/server/app-browser-state.ts` (+52 -1) 📝 `packages/vinext/src/server/app-page-request.ts` (+154 -17) 📝 `pnpm-lock.yaml` (+2 -2) 📝 `tests/__snapshots__/entry-templates.test.ts.snap` (+216 -30) 📝 `tests/app-browser-entry.test.ts` (+83 -0) 📝 `tests/app-page-request.test.ts` (+264 -0) 📝 `tests/e2e/app-router/advanced.spec.ts` (+39 -0) 📝 `tests/entry-templates.test.ts` (+10 -1) ➕ `tests/fixtures/app-basic/app/feed/@modal/(...)photos/[id]/actions.ts` (+13 -0) ➕ `tests/fixtures/app-basic/app/feed/@modal/(...)photos/[id]/like-button.tsx` (+24 -0) 📝 `tests/fixtures/app-basic/app/feed/@modal/(...)photos/[id]/page.tsx` (+6 -1) 📝 `tests/fixtures/static-export/package.json` (+2 -2) </details> ### 📄 Description ## Summary - send interception context and mounted slot headers on app-router server action POSTs using the current browser router state - reuse a shared action rerender target helper so POST rerenders preserve both intercepted source-route trees and current-route slot overrides - add regression coverage for the browser-state helper, generated RSC entry code, and the intercepted modal server-action flow - pin `react` and `react-dom` versions in the `static-export` fixture to match the resolved lockfile state ## Examples - Before: open `/feed`, soft-navigate to `/photos/42`, then trigger a server action from the modal. The POST omitted interception provenance, so the rerender could replace the modal tree with the direct `/photos/[id]` page. After: the same action keeps the modal mounted, keeps the feed layout visible, and leaves the URL at `/photos/42`. - Before: when an intercept resolved back to the current route, the GET path still preserved `interceptOpts` for slot overrides, but the POST rerender path dropped them. After: both GET and POST use the same rerender-target selection logic, so current-route interception shapes keep their slot overrides. - `static-export` fixture dependencies now declare `react` and `react-dom` as `^19.2.5` instead of `catalog:` so the fixture package manifest matches the checked-in lockfile state. ## Testing - `vp test run tests/app-browser-entry.test.ts tests/app-page-request.test.ts tests/entry-templates.test.ts` - `PLAYWRIGHT_PROJECT=app-router vp run test:e2e tests/e2e/app-router/advanced.spec.ts -g 'server action from intercepted modal preserves modal tree'` --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
BreizhHardware 2026-05-06 13:10:43 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/vinext#898
No description provided.