router icon indicating copy to clipboard operation
router copied to clipboard

File lazy loading + SSR hydration issues

Open marbemac opened this issue 1 year ago • 5 comments

Describe the bug

Loading an SSR page that has a lazy file route leads to hydration errors (dev and prod) and a broken app.

Your Example Website or App

examples in this repo

Steps to Reproduce the Bug or Issue

  1. fire up the basic-ssr-file-based example
  2. adjust the index route to be lazy (e.g. index.lazy.tsx and adjusted lazy route export)
  3. reload home page, see error

Additional context

The dynamic import is never invoked on the client on first load.

If you manually adjust the basic-ssr-file-based generated route tree to leverage the old style lazyRouteComponent, the index.lazy.tsx is correctly fetched on page load.

const IndexLazyRoute = createRoute({
  path: '/',
  getParentRoute: () => rootRoute,
  component: lazyRouteComponent(() => {
    console.log('LAZY!!!!')
    return import('./routes/index.lazy')
  }),
})
Screenshot 2024-01-30 at 11 56 46 AM

Compare that to the lazy file route approach and note that index.lazy.tsx is not fetched on page load (I guess the route's lazyFn is never invoked? Haven't dug deep yet), leading to hydration errors and a broken page:

Screenshot 2024-01-30 at 11 59 19 AM

marbemac avatar Jan 30 '24 18:01 marbemac

Will quote my message here that I sent several days ago to discord chat https://discord.com/channels/719702312431386674/1007702008448426065/1201778563528003584

I solved the problem by adding router.load() call before hydration as a temp fix. Seems like current ssr recipes are not stable yet, so we will see.

Hi! I am trying to use @tanstack/react-router with ssr + streaming based on Vinxi + SSR Streaming (file-based) example. Also worth to mention version 1.14.6

Just found out that hydration fails when router migrated to .lazy.tsx files from lazyRouteComponent + .component.tsx.

It seems like it breaks on lazy routes because hydration fails due to absence of component code during hydration. You can find and fix it by adding await router.load() before starting react hydration, but I am not sure if it's correct because load fn is intended to be used on a backend side.

The most common use case for this method is to call it when doing SSR to ensure that all of the critical data for the current route is loaded before attempting to stream or render the application to the client.

It worked like a charm before because of React.lazy wrapper around route.component property, but now it shifted to load component and other lazy code inside router.

I hope it will help someone.

ushakovfserg avatar Jan 31 '24 16:01 ushakovfserg

I'm facing the same issue, really wish there was an example of this in the repository's examples folder so people could know the recommended implementation.

Even though I've used .lazy.tsx I feel like I haven't got the configuration right, sometimes having hydration problems, router infinity errors, and so on.

kcoet avatar Feb 03 '24 06:02 kcoet

I solved the problem by adding router.load() call before hydration as a temp fix.

@kcoet the suggest by @ushakovfserg worked for me - no luck on your end?

Everything seems to be working in the ssr example I put together w SSRx - the load call is here -> https://github.com/TanStack/router/pull/1125/files#diff-e6355028e3797dc040644e9b512ab3da39c1da49fe9ba8af31dcc97abf331abfR13

marbemac avatar Feb 05 '24 16:02 marbemac

@marbemac It doesn't seem to be a problem in tanstack-router, but a problem in my Apollo configuration. I tried modifying it to use codesplitting https://github.com/TanStack/router/tree/main/examples/react/basic-ssr-file-based , it worked fine.

Hoping there's an example of Apollo's use.

kcoet avatar Feb 06 '24 04:02 kcoet

Quick follow-up, while the router.load() call fixes the hydration issues, it also causes the client loaders to fire on initial load. Thus losing some of the benefit of hydrating server fetched data to the client since we're fetching more data than necessary.

marbemac avatar May 11 '24 17:05 marbemac