diff --git a/packages/react-router/src/router.ts b/packages/react-router/src/router.ts
index c81a2d3707..09eac0f673 100644
--- a/packages/react-router/src/router.ts
+++ b/packages/react-router/src/router.ts
@@ -1938,21 +1938,12 @@ export class Router<
if (match.isFetching === 'beforeLoad') {
// If the user doesn't want the route to reload, just
// resolve with the existing loader data
+ // Otherwise, load the route
// if (match.fetchCount && match.status === 'success') {
// resolve()
// }
- // Otherwise, load the route
- matches[index] = match = updateMatch(
- match.id,
- (prev) => ({
- ...prev,
- isFetching: 'loader',
- fetchCount: match.fetchCount + 1,
- }),
- )
-
lazyPromise =
route.lazyFn?.().then((lazyRoute) => {
Object.assign(route.options, lazyRoute.options)
@@ -1978,6 +1969,15 @@ export class Router<
// we can use the options
await lazyPromise
+ matches[index] = match = updateMatch(
+ match.id,
+ (prev) => ({
+ ...prev,
+ isFetching: 'loader',
+ fetchCount: match.fetchCount + 1,
+ }),
+ )
+
checkLatest()
// Kick off the loader!
diff --git a/packages/react-router/tests/components/mockHeavyDependenciesRoute.tsx b/packages/react-router/tests/components/mockHeavyDependenciesRoute.tsx
new file mode 100644
index 0000000000..28e30f9b26
--- /dev/null
+++ b/packages/react-router/tests/components/mockHeavyDependenciesRoute.tsx
@@ -0,0 +1,6 @@
+// This mimicks the waiting of heavy dependencies, which need to be streamed in before the component is available.
+await new Promise((resolve) => setTimeout(resolve, 5000))
+
+export default function HeavyComponent() {
+ return
I am sooo heavy
+}
diff --git a/packages/react-router/tests/createLazyRoute.test.tsx b/packages/react-router/tests/createLazyRoute.test.tsx
new file mode 100644
index 0000000000..da5bedf116
--- /dev/null
+++ b/packages/react-router/tests/createLazyRoute.test.tsx
@@ -0,0 +1,59 @@
+import { afterEach, describe, expect, it, vi } from 'vitest'
+import {
+ RouterHistory,
+ createMemoryHistory,
+ createRootRoute,
+ createRoute,
+ createRouter,
+} from '../src'
+import { cleanup } from '@testing-library/react'
+import { act } from 'react'
+
+afterEach(() => {
+ vi.resetAllMocks()
+ cleanup()
+})
+
+function createTestRouter(initialHistory?: RouterHistory) {
+ const history =
+ initialHistory ?? createMemoryHistory({ initialEntries: ['/'] })
+
+ const rootRoute = createRootRoute({})
+ const indexRoute = createRoute({ getParentRoute: () => rootRoute, path: '/' })
+
+ const heavyRoute = createRoute({
+ getParentRoute: () => rootRoute,
+ path: '/heavy',
+ }).lazy(() => import('./lazy-routes/heavy').then((d) => d.default('/heavy')))
+
+ const routeTree = rootRoute.addChildren([indexRoute, heavyRoute])
+
+ const router = createRouter({ routeTree, history })
+
+ return {
+ router,
+ routes: { indexRoute, heavyRoute },
+ }
+}
+
+describe('preload: matched routes', { timeout: 20000 }, () => {
+ it('should wait for lazy options to be streamed in before ', async () => {
+ const { router } = createTestRouter(
+ createMemoryHistory({ initialEntries: ['/'] }),
+ )
+
+ await router.load()
+
+ // Preload the route and navigate to it
+ router.preloadRoute({ to: '/heavy' })
+ await router.navigate({ to: '/heavy' })
+
+ await router.invalidate()
+
+ expect(router.state.location.pathname).toBe('/heavy')
+
+ const lazyRoute = router.routesByPath['/heavy']
+
+ expect(lazyRoute.options.component).toBeDefined()
+ })
+})
diff --git a/packages/react-router/tests/lazy-routes/heavy.tsx b/packages/react-router/tests/lazy-routes/heavy.tsx
new file mode 100644
index 0000000000..4fbb170742
--- /dev/null
+++ b/packages/react-router/tests/lazy-routes/heavy.tsx
@@ -0,0 +1,8 @@
+import { createLazyRoute } from '../../src'
+import HeavyComponent from '../components/mockHeavyDependenciesRoute'
+
+export default function Route(id: string) {
+ return createLazyRoute(id)({
+ component: HeavyComponent,
+ })
+}