[PR #816] [MERGED] fix: clear stale parallel slots on traversal in mergeElements #866

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

📋 Pull Request Information

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

Base: mainHead: fix/traversal-stale-parallel-slots


📝 Commits (5)

  • a7f6b93 fix: clear stale parallel slots on traversal in mergeElements
  • b4c2b40 refactor: collapse navigate/traverse reducer cases; add UNMATCHED_SLOT traversal test
  • b26a410 refactor: extract toActionType helper; add reducer-level traverse tests
  • 6d23e51 fix ci
  • d996df4 fix ci again

📊 Changes

5 files changed (+137 additions, -7 deletions)

View changed files

📝 packages/vinext/src/server/app-browser-entry.ts (+12 -2)
📝 packages/vinext/src/server/app-browser-state.ts (+5 -4)
📝 packages/vinext/src/shims/slot.tsx (+17 -1)
📝 tests/app-browser-entry.test.ts (+40 -0)
📝 tests/slot.test.ts (+63 -0)

📄 Description

Summary

  • Adds "traverse" as a first-class action type in the router reducer, distinct from "navigate" and "replace"
  • mergeElements gains a clearAbsentSlots flag (default false) that removes slot keys present in prev but absent from next
  • The traverse action type sets this flag, clearing stale parallel slots on browser back/forward
  • Soft forward navigations continue to preserve absent slots (unchanged behavior)

Context

When navigating back from an intercepted route (e.g., /feed with photo modal -> browser back), the RSC response for the destination omits the @modal slot. Previously, mergeElements carried the stale modal forward from prev via { ...prev, ...next }.

The fix cannot simply clear all absent slots because soft forward navigation (e.g., /dashboard -> /dashboard/settings) intentionally omits parent layout slots that haven't changed. Those must be preserved.

The solution: thread the navigation kind through the action type. Browser back/forward dispatches "traverse" instead of "navigate", which tells mergeElements to clear absent slots.

Closes #814

Test plan

  • Unit test: mergeElements clears stale slots absent from next when clearAbsentSlots is set
  • Unit test: mergeElements preserves absent slots when clearAbsentSlots is not set
  • Existing mergeElements tests pass (UNMATCHED_SLOT preservation, shallow merge)
  • E2E: parallel slot content persists on soft navigation to child route (existing, should still pass in CI)
  • E2E: back/forward on intercepted routes (depends on #753 fixtures, tracked separately)

🔄 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/816 **Author:** [@NathanDrake2406](https://github.com/NathanDrake2406) **Created:** 4/10/2026 **Status:** ✅ Merged **Merged:** 4/10/2026 **Merged by:** [@james-elicx](https://github.com/james-elicx) **Base:** `main` ← **Head:** `fix/traversal-stale-parallel-slots` --- ### 📝 Commits (5) - [`a7f6b93`](https://github.com/cloudflare/vinext/commit/a7f6b9396b747113a48ec4e9aedd80bc1e37bbd7) fix: clear stale parallel slots on traversal in mergeElements - [`b4c2b40`](https://github.com/cloudflare/vinext/commit/b4c2b403bb4a7d91622a9f3531a85a5475a12d07) refactor: collapse navigate/traverse reducer cases; add UNMATCHED_SLOT traversal test - [`b26a410`](https://github.com/cloudflare/vinext/commit/b26a410a812b6a173f492c0acb0b0e67cfe4f5fd) refactor: extract toActionType helper; add reducer-level traverse tests - [`6d23e51`](https://github.com/cloudflare/vinext/commit/6d23e5157fe3c4b54a4736eee9a10df66676366c) fix ci - [`d996df4`](https://github.com/cloudflare/vinext/commit/d996df450a75e284ed1b60618afd434bf0569d8e) fix ci again ### 📊 Changes **5 files changed** (+137 additions, -7 deletions) <details> <summary>View changed files</summary> 📝 `packages/vinext/src/server/app-browser-entry.ts` (+12 -2) 📝 `packages/vinext/src/server/app-browser-state.ts` (+5 -4) 📝 `packages/vinext/src/shims/slot.tsx` (+17 -1) 📝 `tests/app-browser-entry.test.ts` (+40 -0) 📝 `tests/slot.test.ts` (+63 -0) </details> ### 📄 Description ## Summary - Adds `"traverse"` as a first-class action type in the router reducer, distinct from `"navigate"` and `"replace"` - `mergeElements` gains a `clearAbsentSlots` flag (default false) that removes slot keys present in `prev` but absent from `next` - The traverse action type sets this flag, clearing stale parallel slots on browser back/forward - Soft forward navigations continue to preserve absent slots (unchanged behavior) ## Context When navigating back from an intercepted route (e.g., `/feed` with photo modal -> browser back), the RSC response for the destination omits the `@modal` slot. Previously, `mergeElements` carried the stale modal forward from `prev` via `{ ...prev, ...next }`. The fix cannot simply clear all absent slots because soft forward navigation (e.g., `/dashboard` -> `/dashboard/settings`) intentionally omits parent layout slots that haven't changed. Those must be preserved. The solution: thread the navigation kind through the action type. Browser back/forward dispatches `"traverse"` instead of `"navigate"`, which tells `mergeElements` to clear absent slots. Closes #814 ## Test plan - [x] Unit test: `mergeElements clears stale slots absent from next when clearAbsentSlots is set` - [x] Unit test: `mergeElements preserves absent slots when clearAbsentSlots is not set` - [x] Existing `mergeElements` tests pass (UNMATCHED_SLOT preservation, shallow merge) - [ ] E2E: `parallel slot content persists on soft navigation to child route` (existing, should still pass in CI) - [ ] E2E: back/forward on intercepted routes (depends on #753 fixtures, tracked separately) --- <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:33 +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#866
No description provided.