@tanstack/router-core 1.131.16 → 1.131.18

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/router-core",
3
- "version": "1.131.16",
3
+ "version": "1.131.18",
4
4
  "description": "Modern and scalable routing for React applications",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
package/src/router.ts CHANGED
@@ -2318,11 +2318,9 @@ export class RouterCore<
2318
2318
  const match = this.getMatch(matchId)!
2319
2319
  if (shouldPending && match._nonReactive.pendingTimeout === undefined) {
2320
2320
  const pendingTimeout = setTimeout(() => {
2321
- try {
2322
- // Update the match and prematurely resolve the loadMatches promise so that
2323
- // the pending component can start rendering
2324
- this.triggerOnReady(innerLoadContext)
2325
- } catch {}
2321
+ // Update the match and prematurely resolve the loadMatches promise so that
2322
+ // the pending component can start rendering
2323
+ this.triggerOnReady(innerLoadContext)
2326
2324
  }, pendingMs)
2327
2325
  match._nonReactive.pendingTimeout = pendingTimeout
2328
2326
  }
@@ -2371,131 +2369,150 @@ export class RouterCore<
2371
2369
  index: number,
2372
2370
  route: AnyRoute,
2373
2371
  ): void | Promise<void> => {
2374
- const resolve = () => {
2375
- innerLoadContext.updateMatch(matchId, (prev) => {
2376
- prev._nonReactive.beforeLoadPromise?.resolve()
2377
- prev._nonReactive.beforeLoadPromise = undefined
2372
+ const match = this.getMatch(matchId)!
2378
2373
 
2379
- return {
2380
- ...prev,
2381
- isFetching: false,
2382
- }
2383
- })
2384
- }
2374
+ match._nonReactive.beforeLoadPromise = createControlledPromise<void>()
2375
+ // explicitly capture the previous loadPromise
2376
+ const prevLoadPromise = match._nonReactive.loadPromise
2377
+ match._nonReactive.loadPromise = createControlledPromise<void>(() => {
2378
+ prevLoadPromise?.resolve()
2379
+ })
2385
2380
 
2386
- try {
2387
- const match = this.getMatch(matchId)!
2388
- match._nonReactive.beforeLoadPromise = createControlledPromise<void>()
2389
- // explicitly capture the previous loadPromise
2390
- const prevLoadPromise = match._nonReactive.loadPromise
2391
- match._nonReactive.loadPromise = createControlledPromise<void>(() => {
2392
- prevLoadPromise?.resolve()
2393
- })
2381
+ const { paramsError, searchError } = match
2394
2382
 
2395
- const { paramsError, searchError } = this.getMatch(matchId)!
2383
+ if (paramsError) {
2384
+ this.handleSerialError(
2385
+ innerLoadContext,
2386
+ index,
2387
+ paramsError,
2388
+ 'PARSE_PARAMS',
2389
+ )
2390
+ }
2396
2391
 
2397
- if (paramsError) {
2398
- this.handleSerialError(
2399
- innerLoadContext,
2400
- index,
2401
- paramsError,
2402
- 'PARSE_PARAMS',
2403
- )
2404
- }
2392
+ if (searchError) {
2393
+ this.handleSerialError(
2394
+ innerLoadContext,
2395
+ index,
2396
+ searchError,
2397
+ 'VALIDATE_SEARCH',
2398
+ )
2399
+ }
2405
2400
 
2406
- if (searchError) {
2407
- this.handleSerialError(
2408
- innerLoadContext,
2409
- index,
2410
- searchError,
2411
- 'VALIDATE_SEARCH',
2412
- )
2413
- }
2401
+ this.setupPendingTimeout(innerLoadContext, matchId, route)
2414
2402
 
2415
- this.setupPendingTimeout(innerLoadContext, matchId, route)
2403
+ const abortController = new AbortController()
2416
2404
 
2417
- const abortController = new AbortController()
2405
+ const parentMatchId = innerLoadContext.matches[index - 1]?.id
2406
+ const parentMatch = parentMatchId
2407
+ ? this.getMatch(parentMatchId)!
2408
+ : undefined
2409
+ const parentMatchContext =
2410
+ parentMatch?.context ?? this.options.context ?? undefined
2418
2411
 
2419
- const parentMatchId = innerLoadContext.matches[index - 1]?.id
2420
- const parentMatch = parentMatchId
2421
- ? this.getMatch(parentMatchId)!
2422
- : undefined
2423
- const parentMatchContext =
2424
- parentMatch?.context ?? this.options.context ?? undefined
2412
+ const context = { ...parentMatchContext, ...match.__routeContext }
2425
2413
 
2414
+ let isPending = false
2415
+ const pending = () => {
2416
+ if (isPending) return
2417
+ isPending = true
2426
2418
  innerLoadContext.updateMatch(matchId, (prev) => ({
2427
2419
  ...prev,
2428
2420
  isFetching: 'beforeLoad',
2429
2421
  fetchCount: prev.fetchCount + 1,
2430
2422
  abortController,
2431
- context: {
2432
- ...parentMatchContext,
2433
- ...prev.__routeContext,
2434
- },
2423
+ context,
2435
2424
  }))
2425
+ }
2436
2426
 
2437
- const { search, params, context, cause } = this.getMatch(matchId)!
2427
+ const resolve = () => {
2428
+ match._nonReactive.beforeLoadPromise?.resolve()
2429
+ match._nonReactive.beforeLoadPromise = undefined
2430
+ innerLoadContext.updateMatch(matchId, (prev) => ({
2431
+ ...prev,
2432
+ isFetching: false,
2433
+ }))
2434
+ }
2438
2435
 
2439
- const preload = this.resolvePreload(innerLoadContext, matchId)
2436
+ // if there is no `beforeLoad` option, skip everything, batch update the store, return early
2437
+ if (!route.options.beforeLoad) {
2438
+ batch(() => {
2439
+ pending()
2440
+ resolve()
2441
+ })
2442
+ return
2443
+ }
2440
2444
 
2441
- const beforeLoadFnContext: BeforeLoadContextOptions<
2442
- any,
2443
- any,
2444
- any,
2445
- any,
2446
- any
2447
- > = {
2448
- search,
2449
- abortController,
2450
- params,
2451
- preload,
2452
- context,
2453
- location: innerLoadContext.location,
2454
- navigate: (opts: any) =>
2455
- this.navigate({ ...opts, _fromLocation: innerLoadContext.location }),
2456
- buildLocation: this.buildLocation,
2457
- cause: preload ? 'preload' : cause,
2458
- matches: innerLoadContext.matches,
2459
- }
2445
+ const { search, params, cause } = match
2446
+ const preload = this.resolvePreload(innerLoadContext, matchId)
2447
+ const beforeLoadFnContext: BeforeLoadContextOptions<
2448
+ any,
2449
+ any,
2450
+ any,
2451
+ any,
2452
+ any
2453
+ > = {
2454
+ search,
2455
+ abortController,
2456
+ params,
2457
+ preload,
2458
+ context,
2459
+ location: innerLoadContext.location,
2460
+ navigate: (opts: any) =>
2461
+ this.navigate({ ...opts, _fromLocation: innerLoadContext.location }),
2462
+ buildLocation: this.buildLocation,
2463
+ cause: preload ? 'preload' : cause,
2464
+ matches: innerLoadContext.matches,
2465
+ }
2460
2466
 
2461
- const updateContext = (beforeLoadContext: any) => {
2462
- if (isRedirect(beforeLoadContext) || isNotFound(beforeLoadContext)) {
2463
- this.handleSerialError(
2464
- innerLoadContext,
2465
- index,
2466
- beforeLoadContext,
2467
- 'BEFORE_LOAD',
2468
- )
2469
- }
2467
+ const updateContext = (beforeLoadContext: any) => {
2468
+ if (beforeLoadContext === undefined) {
2469
+ batch(() => {
2470
+ pending()
2471
+ resolve()
2472
+ })
2473
+ return
2474
+ }
2475
+ if (isRedirect(beforeLoadContext) || isNotFound(beforeLoadContext)) {
2476
+ pending()
2477
+ this.handleSerialError(
2478
+ innerLoadContext,
2479
+ index,
2480
+ beforeLoadContext,
2481
+ 'BEFORE_LOAD',
2482
+ )
2483
+ }
2470
2484
 
2485
+ batch(() => {
2486
+ pending()
2471
2487
  innerLoadContext.updateMatch(matchId, (prev) => ({
2472
2488
  ...prev,
2473
2489
  __beforeLoadContext: beforeLoadContext,
2474
2490
  context: {
2475
- ...parentMatchContext,
2476
- ...prev.__routeContext,
2491
+ ...prev.context,
2477
2492
  ...beforeLoadContext,
2478
2493
  },
2479
- abortController,
2480
2494
  }))
2481
- }
2495
+ resolve()
2496
+ })
2497
+ }
2482
2498
 
2483
- const beforeLoadContext = route.options.beforeLoad?.(beforeLoadFnContext)
2499
+ let beforeLoadContext
2500
+ try {
2501
+ beforeLoadContext = route.options.beforeLoad(beforeLoadFnContext)
2484
2502
  if (isPromise(beforeLoadContext)) {
2503
+ pending()
2485
2504
  return beforeLoadContext
2486
- .then(updateContext)
2487
2505
  .catch((err) => {
2488
2506
  this.handleSerialError(innerLoadContext, index, err, 'BEFORE_LOAD')
2489
2507
  })
2490
- .then(resolve)
2491
- } else {
2492
- updateContext(beforeLoadContext)
2508
+ .then(updateContext)
2493
2509
  }
2494
2510
  } catch (err) {
2511
+ pending()
2495
2512
  this.handleSerialError(innerLoadContext, index, err, 'BEFORE_LOAD')
2496
2513
  }
2497
2514
 
2498
- resolve()
2515
+ updateContext(beforeLoadContext)
2499
2516
  return
2500
2517
  }
2501
2518
 
@@ -2680,10 +2697,12 @@ export class RouterCore<
2680
2697
  this.getMatch(matchId),
2681
2698
  loaderData,
2682
2699
  )
2683
- innerLoadContext.updateMatch(matchId, (prev) => ({
2684
- ...prev,
2685
- loaderData,
2686
- }))
2700
+ if (loaderData !== undefined) {
2701
+ innerLoadContext.updateMatch(matchId, (prev) => ({
2702
+ ...prev,
2703
+ loaderData,
2704
+ }))
2705
+ }
2687
2706
  }
2688
2707
 
2689
2708
  // Lazy option can modify the route options,
@@ -2709,7 +2728,8 @@ export class RouterCore<
2709
2728
  } catch (e) {
2710
2729
  let error = e
2711
2730
 
2712
- await this.potentialPendingMinPromise(matchId)
2731
+ const pendingPromise = this.potentialPendingMinPromise(matchId)
2732
+ if (pendingPromise) await pendingPromise
2713
2733
 
2714
2734
  this.handleRedirectAndNotFound(
2715
2735
  innerLoadContext,
@@ -2819,14 +2839,16 @@ export class RouterCore<
2819
2839
  )
2820
2840
  : shouldReloadOption
2821
2841
 
2822
- innerLoadContext.updateMatch(matchId, (prev) => {
2823
- prev._nonReactive.loaderPromise = createControlledPromise<void>()
2824
- return {
2842
+ const nextPreload =
2843
+ !!preload && !this.state.matches.some((d) => d.id === matchId)
2844
+ const match = this.getMatch(matchId)!
2845
+ match._nonReactive.loaderPromise = createControlledPromise<void>()
2846
+ if (nextPreload !== match.preload) {
2847
+ innerLoadContext.updateMatch(matchId, (prev) => ({
2825
2848
  ...prev,
2826
- preload:
2827
- !!preload && !this.state.matches.some((d) => d.id === matchId),
2828
- }
2829
- })
2849
+ preload: nextPreload,
2850
+ }))
2851
+ }
2830
2852
 
2831
2853
  // If the route is successful and still fresh, just resolve
2832
2854
  const { status, invalid } = this.getMatch(matchId)!
@@ -2868,23 +2890,24 @@ export class RouterCore<
2868
2890
  }
2869
2891
  }
2870
2892
  }
2893
+ const match = this.getMatch(matchId)!
2871
2894
  if (!loaderIsRunningAsync) {
2872
- const match = this.getMatch(matchId)!
2873
2895
  match._nonReactive.loaderPromise?.resolve()
2874
2896
  match._nonReactive.loadPromise?.resolve()
2875
2897
  }
2876
2898
 
2877
- innerLoadContext.updateMatch(matchId, (prev) => {
2878
- clearTimeout(prev._nonReactive.pendingTimeout)
2879
- prev._nonReactive.pendingTimeout = undefined
2880
- if (!loaderIsRunningAsync) prev._nonReactive.loaderPromise = undefined
2881
- prev._nonReactive.dehydrated = undefined
2882
- return {
2899
+ clearTimeout(match._nonReactive.pendingTimeout)
2900
+ match._nonReactive.pendingTimeout = undefined
2901
+ if (!loaderIsRunningAsync) match._nonReactive.loaderPromise = undefined
2902
+ match._nonReactive.dehydrated = undefined
2903
+ const nextIsFetching = loaderIsRunningAsync ? match.isFetching : false
2904
+ if (nextIsFetching !== match.isFetching || match.invalid !== false) {
2905
+ innerLoadContext.updateMatch(matchId, (prev) => ({
2883
2906
  ...prev,
2884
- isFetching: loaderIsRunningAsync ? prev.isFetching : false,
2907
+ isFetching: nextIsFetching,
2885
2908
  invalid: false,
2886
- }
2887
- })
2909
+ }))
2910
+ }
2888
2911
  return this.getMatch(matchId)!
2889
2912
  }
2890
2913