Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Oct 21, 2025

Overview

This PR significantly improves the client-side navigation implementation in the RSC examples to be production-ready, addressing requirements from the original issue and issue #795.

Changes

1. Coordinated History and Transition Handling

The old implementation called onNavigation() synchronously after history.pushState(), which could cause jarring updates where the URL changes but the page hasn't rendered yet.

Improvements:

  • Navigation callbacks are now wrapped in React.startTransition() to coordinate with React's concurrent rendering
  • URL updates happen immediately (via history.pushState/replaceState) for instant user feedback
  • Page rendering is deferred and can be interrupted if needed
  • Added pendingNavigationUrl tracking to prevent race conditions
// Before
window.history.pushState = function (...args) {
  const res = oldPushState.apply(this, args)
  onNavigation()  // Synchronous, blocks URL update
  return res
}

// After
window.history.pushState = function (...args) {
  const res = oldPushState.apply(this, args)
  React.startTransition(() => {
    onNavigation()  // Deferred, doesn't block URL update
  })
  return res
}

Reference: Inspired by https://github.com/hi-ogawa/reproductions/tree/main/vite-rsc-coordinate-history-and-transition

2. Back/Forward Cache Support

Previously, every back/forward navigation required a full re-fetch from the server, causing noticeable delays especially for content-heavy pages.

Improvements:

  • Implemented navigationCache Map to store visited pages
  • Back/forward navigation checks cache first and uses cached payload for instant navigation
  • Falls back to server fetch if page not in cache
  • Current page is cached before navigating away

This is especially important for documentation sites and content-heavy applications where users frequently use browser navigation buttons.

Reference: Addresses requirements from https://github.com/hi-ogawa/rscpress

3. Navigation Cancellation

Improvements:

  • Added AbortController to cancel pending navigations
  • When user navigates to a new page while previous navigation is pending, the old one is cancelled
  • Prevents race conditions and ensures data consistency

4. Comprehensive Error Handling

Addresses issue #795 with proper error handling throughout the navigation and rendering pipeline.

Browser (entry.browser.tsx):

  • Added onError callbacks to all createFromReadableStream and createFromFetch calls
  • Error boundary-like display for navigation errors with reload option
  • Try-catch blocks for server function calls with proper error propagation
  • Detailed console logging for debugging
const payload = await createFromFetch<RscPayload>(
  fetch(window.location.href),
  {
    onError(error: unknown) {
      console.error('[rsc] Failed to deserialize RSC payload:', error)
    },
  },
)

SSR (entry.ssr.tsx):

  • Added onError callback to renderToReadableStream with error digest and component stack
  • Added onError callback to createFromReadableStream for RSC deserialization errors
  • Comprehensive error logging for production debugging
const htmlStream = await renderToReadableStream(<SsrRoot />, {
  // ... other options
  onError(error: unknown, errorInfo: { digest?: string; componentStack?: string }) {
    console.error('[ssr] Rendering error:', error)
    if (errorInfo.digest) {
      console.error('[ssr] Error digest:', errorInfo.digest)
    }
    if (errorInfo.componentStack) {
      console.error('[ssr] Component stack:', errorInfo.componentStack)
    }
  },
})

Reference: Addresses issue #795 - #795

5. Demo Navigation Links

Added navigation links to the starter example to demonstrate the improvements:

Navigation Demo

The demo shows:

  • Smooth client-side page transitions
  • Instant back/forward navigation with caching
  • URL updates immediately while content loads seamlessly

Files Changed

  • packages/plugin-rsc/examples/starter/src/framework/entry.browser.tsx - Improved navigation logic
  • packages/plugin-rsc/examples/basic/src/framework/entry.browser.tsx - Improved navigation logic
  • packages/plugin-rsc/examples/starter/src/framework/entry.ssr.tsx - Added error handling
  • packages/plugin-rsc/examples/basic/src/framework/entry.ssr.tsx - Added error handling
  • packages/plugin-rsc/examples/starter/src/root.tsx - Added demo navigation links

Testing

  • ✅ All unit tests pass (57 tests)
  • ✅ E2E tests pass (107 passed, 27 skipped HMR tests)
  • ✅ TypeScript compilation successful
  • ✅ ESLint validation passes
  • ✅ Manual testing verified navigation, back/forward, and error handling
  • ✅ CodeQL security analysis: No vulnerabilities found

Breaking Changes

None. These are improvements to example code only.

Related Issues

Closes #<issue_number>
Addresses #795

Credits

Thanks to @hi-ogawa for the issue report and reference implementations.

Original prompt

This section details on the original issue you should resolve

<issue_title>improve client side navigation example</issue_title>
<issue_description>The demo code might be too simple and we probably want this logic at least https://github.com/hi-ogawa/reproductions/tree/main/vite-rsc-coordinate-history-and-transition and also back/forward cache, which should be a minimal requirement for simple doc site for example https://github.com/hi-ogawa/rscpress.

This should also take into account error handling #795</issue_description>

Comments on the Issue (you are @copilot in this section)

Fixes #860


💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click here to start the survey.

Copilot AI and others added 2 commits October 21, 2025 12:40
…dling

Co-authored-by: hi-ogawa <4232207+hi-ogawa@users.noreply.github.com>
Co-authored-by: hi-ogawa <4232207+hi-ogawa@users.noreply.github.com>
Copilot AI changed the title [WIP] Improve client side navigation example feat(plugin-rsc): improve client-side navigation with transitions, cache, and error handling Oct 21, 2025
Copilot AI requested a review from hi-ogawa October 21, 2025 12:54
Copilot finished work on behalf of hi-ogawa October 21, 2025 12:54
@hi-ogawa
Copy link
Contributor

@hi-ogawa hi-ogawa closed this Oct 23, 2025
@hi-ogawa hi-ogawa deleted the copilot/improve-client-navigation-example branch October 23, 2025 00:03
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