Skip to content

Conversation

@hi-ogawa
Copy link
Contributor

@hi-ogawa hi-ogawa commented Oct 22, 2025

TODO

  • compare with next.js
  • compare with async react demo
  • test
    • URL update coordination
    • interruptible navigation
    • back forward cache
      • invalidate on hmr
      • invalidate on action
  • split back forward cache?
  • navigation API

…story and transitions

Add a new example that demonstrates how to properly coordinate browser
history navigation with React transitions in RSC applications.

Key features:
- Dispatch-based navigation coordination pattern
- History updates via useInsertionEffect after state updates
- Promise-based navigation state with React.use()
- Visual feedback with transition status indicator
- Prevents race conditions with rapid navigation
- Proper back/forward navigation support

This pattern is inspired by Next.js App Router implementation and
addresses common issues with client-side navigation in RSC apps:
- URL bar staying in sync with rendered content
- Proper loading state management
- Race condition prevention
- Coordinated back/forward navigation

Based on: https://github.com/hi-ogawa/reproductions/tree/main/vite-rsc-coordinate-history-and-transition
Related to: vitejs#860

Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Implement instant back/forward navigation using history-state-keyed cache:

- Cache maps history.state.key → Promise<RscPayload>
- Cache hit: synchronous render, no loading state
- Cache miss: async fetch, shows transition
- Server actions update cache for current entry
- Each history entry gets unique random key

This pattern enables:
- Instant back/forward navigation (no server fetch)
- Proper cache invalidation after mutations
- Browser-native scroll restoration
- Loading states only for actual fetches

Based on: https://github.com/hi-ogawa/vite-environment-examples/blob/main/examples/react-server/src/features/router/browser.ts

Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Consolidate all navigation logic into a single Router class for better
organization and maintainability.

Before: Logic was fragmented across module-level variables (dispatch,
bfCache), standalone functions (listenNavigation, addStateKey), and
separate components (HistoryUpdater).

After: Single Router class encapsulates:
- Navigation state management
- Back/forward cache
- History interception (pushState/replaceState/popstate)
- Link click handling
- React integration via setReactHandlers()

API:
- new Router(initialPayload) - create instance
- router.setReactHandlers(setState, startTransition) - connect to React
- router.listen() - setup listeners, returns cleanup
- router.navigate(url, push) - navigate to URL
- router.handleServerAction(payload) - handle server action
- router.invalidateCache() - invalidate cache
- router.commitHistoryPush(url) - commit push (useInsertionEffect)

Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Remove src/framework/react.d.ts (types now in tsconfig)
- Replace tsconfig.json with starter example config
- Uses @vitejs/plugin-rsc/types for type definitions

Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Remove vite-plugin-inspect dependency and usage to simplify the example.

Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Extract Router and BackForwardCache classes to src/framework/router.ts
for better code organization and reusability.

- Created router.ts with Router and BackForwardCache classes
- Exported NavigationState type
- Updated entry.browser.tsx to import from router module
- entry.browser.tsx now focuses on React integration

Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Rename for clarity:
- router.ts → navigation.ts
- Router class → NavigationManager class

"NavigationManager" better describes the class's responsibility of
managing all navigation concerns (history, cache, transitions).

Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Add modern Navigation API support with automatic fallback to History API.

Navigation API benefits:
- Built-in unique keys per entry (navigation.currentEntry.key)
- Single 'navigate' event replaces pushState/replaceState/popstate
- e.canIntercept checks if navigation is interceptable
- e.intercept() is cleaner than preventDefault + manual state
- No useInsertionEffect coordination needed

Implementation:
- Feature detection: 'navigation' in window
- NavigationManager.listenNavigationAPI() for modern browsers
- NavigationManager.listenHistoryAPI() for fallback
- BackForwardCache.getCurrentKey() uses appropriate source

Browser support:
- Navigation API: Chrome 102+, Edge 102+
- History API fallback: All browsers

https://developer.mozilla.org/en-US/docs/Web/API/Navigation_API

Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@hi-ogawa hi-ogawa changed the title feat(plugin-rsc): add navigation example with coordinated history and transition chore(rsc): add navigation example with coordinated history and transition Oct 29, 2025
@hi-ogawa hi-ogawa changed the title chore(rsc): add navigation example with coordinated history and transition chore(rsc): add example of coordinating browser URL update with React transition Oct 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

improve client side navigation example

2 participants