@tanstack/react-router 1.86.0 → 1.87.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/react-router",
3
- "version": "1.86.0",
3
+ "version": "1.87.0",
4
4
  "description": "Modern and scalable routing for React applications",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
package/src/router.ts CHANGED
@@ -1743,7 +1743,6 @@ export class Router<
1743
1743
  }
1744
1744
  maskedNext = build(maskedDest)
1745
1745
  }
1746
- // console.log('buildWithMatches', {foundMask, dest, maskedDest, maskedNext})
1747
1746
  }
1748
1747
 
1749
1748
  const nextMatches = this.getMatchedRoutes(next, dest)
@@ -2118,19 +2117,24 @@ export class Router<
2118
2117
  let updated!: AnyRouteMatch
2119
2118
  const isPending = this.state.pendingMatches?.find((d) => d.id === id)
2120
2119
  const isMatched = this.state.matches.find((d) => d.id === id)
2120
+ const isCached = this.state.cachedMatches.find((d) => d.id === id)
2121
2121
 
2122
2122
  const matchesKey = isPending
2123
2123
  ? 'pendingMatches'
2124
2124
  : isMatched
2125
2125
  ? 'matches'
2126
- : 'cachedMatches'
2126
+ : isCached
2127
+ ? 'cachedMatches'
2128
+ : ''
2127
2129
 
2128
- this.__store.setState((s) => ({
2129
- ...s,
2130
- [matchesKey]: s[matchesKey]?.map((d) =>
2131
- d.id === id ? (updated = updater(d)) : d,
2132
- ),
2133
- }))
2130
+ if (matchesKey) {
2131
+ this.__store.setState((s) => ({
2132
+ ...s,
2133
+ [matchesKey]: s[matchesKey]?.map((d) =>
2134
+ d.id === id ? (updated = updater(d)) : d,
2135
+ ),
2136
+ }))
2137
+ }
2134
2138
 
2135
2139
  return updated
2136
2140
  }
@@ -2146,7 +2150,7 @@ export class Router<
2146
2150
  loadMatches = async ({
2147
2151
  location,
2148
2152
  matches,
2149
- preload,
2153
+ preload: allPreload,
2150
2154
  onReady,
2151
2155
  updateMatch = this.updateMatch,
2152
2156
  }: {
@@ -2170,6 +2174,10 @@ export class Router<
2170
2174
  }
2171
2175
  }
2172
2176
 
2177
+ const resolvePreload = (matchId: string) => {
2178
+ return !!(allPreload && !this.state.matches.find((d) => d.id === matchId))
2179
+ }
2180
+
2173
2181
  if (!this.isServer && !this.state.matches.length) {
2174
2182
  triggerOnReady()
2175
2183
  }
@@ -2270,7 +2278,7 @@ export class Router<
2270
2278
  const shouldPending = !!(
2271
2279
  onReady &&
2272
2280
  !this.isServer &&
2273
- !preload &&
2281
+ !resolvePreload(matchId) &&
2274
2282
  (route.options.loader || route.options.beforeLoad) &&
2275
2283
  typeof pendingMs === 'number' &&
2276
2284
  pendingMs !== Infinity &&
@@ -2354,6 +2362,8 @@ export class Router<
2354
2362
  const { search, params, context, cause } =
2355
2363
  this.getMatch(matchId)!
2356
2364
 
2365
+ const preload = resolvePreload(matchId)
2366
+
2357
2367
  const beforeLoadFnContext: BeforeLoadContextOptions<
2358
2368
  any,
2359
2369
  any,
@@ -2364,7 +2374,7 @@ export class Router<
2364
2374
  search,
2365
2375
  abortController,
2366
2376
  params,
2367
- preload: !!preload,
2377
+ preload,
2368
2378
  context,
2369
2379
  location,
2370
2380
  navigate: (opts: any) =>
@@ -2432,7 +2442,9 @@ export class Router<
2432
2442
  (async () => {
2433
2443
  const { loaderPromise: prevLoaderPromise } =
2434
2444
  this.getMatch(matchId)!
2445
+
2435
2446
  let loaderRunningAsync = false
2447
+
2436
2448
  if (prevLoaderPromise) {
2437
2449
  await prevLoaderPromise
2438
2450
  } else {
@@ -2448,6 +2460,8 @@ export class Router<
2448
2460
  cause,
2449
2461
  } = this.getMatch(matchId)!
2450
2462
 
2463
+ const preload = resolvePreload(matchId)
2464
+
2451
2465
  return {
2452
2466
  params,
2453
2467
  deps: loaderDeps,
@@ -2466,6 +2480,8 @@ export class Router<
2466
2480
  // This is where all of the stale-while-revalidate magic happens
2467
2481
  const age = Date.now() - this.getMatch(matchId)!.updatedAt
2468
2482
 
2483
+ const preload = resolvePreload(matchId)
2484
+
2469
2485
  const staleAge = preload
2470
2486
  ? (route.options.preloadStaleTime ??
2471
2487
  this.options.defaultPreloadStaleTime ??
@@ -2580,6 +2596,8 @@ export class Router<
2580
2596
  loaderData,
2581
2597
  })
2582
2598
  const meta = headFnContent?.meta
2599
+ const links = headFnContent?.links
2600
+ const scripts = headFnContent?.scripts
2583
2601
 
2584
2602
  const headers = route.options.headers?.({
2585
2603
  loaderData,
@@ -2593,6 +2611,8 @@ export class Router<
2593
2611
  updatedAt: Date.now(),
2594
2612
  loaderData,
2595
2613
  meta,
2614
+ links,
2615
+ scripts,
2596
2616
  headers,
2597
2617
  }))
2598
2618
  } catch (e) {
@@ -2682,7 +2702,7 @@ export class Router<
2682
2702
  await triggerOnReady()
2683
2703
  } catch (err) {
2684
2704
  if (isRedirect(err) || isNotFound(err)) {
2685
- if (isNotFound(err) && !preload) {
2705
+ if (isNotFound(err) && !allPreload) {
2686
2706
  await triggerOnReady()
2687
2707
  }
2688
2708
  throw err
@@ -2802,17 +2822,21 @@ export class Router<
2802
2822
  dest: opts,
2803
2823
  })
2804
2824
 
2805
- const loadedMatchIds = Object.fromEntries(
2806
- [
2807
- ...this.state.matches,
2808
- ...(this.state.pendingMatches ?? []),
2809
- ...this.state.cachedMatches,
2810
- ].map((d) => [d.id, true]),
2825
+ const activeMatchIds = new Set(
2826
+ [...this.state.matches, ...(this.state.pendingMatches ?? [])].map(
2827
+ (d) => d.id,
2828
+ ),
2811
2829
  )
2812
2830
 
2831
+ const loadedMatchIds = new Set([
2832
+ ...activeMatchIds,
2833
+ ...this.state.cachedMatches.map((d) => d.id),
2834
+ ])
2835
+
2836
+ // If the matches are already loaded, we need to add them to the cachedMatches
2813
2837
  this.__store.batch(() => {
2814
2838
  matches.forEach((match) => {
2815
- if (!loadedMatchIds[match.id]) {
2839
+ if (!loadedMatchIds.has(match.id)) {
2816
2840
  this.__store.setState((s) => ({
2817
2841
  ...s,
2818
2842
  cachedMatches: [...(s.cachedMatches as any), match],
@@ -2821,18 +2845,13 @@ export class Router<
2821
2845
  })
2822
2846
  })
2823
2847
 
2824
- const activeMatchIds = new Set(
2825
- [...this.state.matches, ...(this.state.pendingMatches ?? [])].map(
2826
- (d) => d.id,
2827
- ),
2828
- )
2829
-
2830
2848
  try {
2831
2849
  matches = await this.loadMatches({
2832
2850
  matches,
2833
2851
  location: next,
2834
2852
  preload: true,
2835
2853
  updateMatch: (id, updater) => {
2854
+ // Don't update the match if it's currently loaded
2836
2855
  if (activeMatchIds.has(id)) {
2837
2856
  matches = matches.map((d) => (d.id === id ? updater(d) : d))
2838
2857
  } else {