@tanstack/router-core 0.0.1-beta.177 → 0.0.1-beta.179

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,7 +1,7 @@
1
1
  {
2
2
  "name": "@tanstack/router-core",
3
3
  "author": "Tanner Linsley",
4
- "version": "0.0.1-beta.177",
4
+ "version": "0.0.1-beta.179",
5
5
  "license": "MIT",
6
6
  "repository": "tanstack/router",
7
7
  "homepage": "https://tanstack.com/router",
package/src/route.ts CHANGED
@@ -254,7 +254,6 @@ export type BaseRouteOptions<
254
254
  TRouteContext extends RouteContext = RouteContext,
255
255
  TAllContext extends AnyContext = AnyContext,
256
256
  > = RoutePathOptions<TCustomId, TPath> & {
257
- layoutLimit?: string
258
257
  getParentRoute: () => TParentRoute
259
258
  validateSearch?: SearchSchemaValidator<TSearchSchema>
260
259
  loader?: LoaderFn<
@@ -265,7 +264,34 @@ export type BaseRouteOptions<
265
264
  NoInfer<TRouteContext>,
266
265
  TAllContext
267
266
  >
268
- } & ([TLoader] extends [never]
267
+ } & (keyof PickRequired<RouteContext> extends never
268
+ ? // This async function is called before a route is loaded.
269
+ // If an error is thrown here, the route's loader will not be called.
270
+ // If thrown during a navigation, the navigation will be cancelled and the error will be passed to the `onError` function.
271
+ // If thrown during a preload event, the error will be logged to the console.
272
+ {
273
+ beforeLoad?: BeforeLoadFn<
274
+ TParentRoute,
275
+ TAllParams,
276
+ TSearchSchema,
277
+ TFullSearchSchema,
278
+ TParentContext,
279
+ TAllParentContext,
280
+ TRouteContext
281
+ >
282
+ }
283
+ : {
284
+ beforeLoad: BeforeLoadFn<
285
+ TParentRoute,
286
+ TAllParams,
287
+ TSearchSchema,
288
+ TFullSearchSchema,
289
+ TParentContext,
290
+ TAllParentContext,
291
+ TRouteContext
292
+ >
293
+ }) &
294
+ ([TLoader] extends [never]
269
295
  ? {
270
296
  loader: 'Loaders must return a type other than never. If you are throwing a redirect() and not returning anything, return a redirect() instead.'
271
297
  }
@@ -286,32 +312,12 @@ export type BaseRouteOptions<
286
312
  stringifyParams?: never
287
313
  parseParams?: never
288
314
  }
289
- ) &
290
- (keyof PickRequired<RouteContext> extends never
291
- ? {
292
- getContext?: GetContextFn<
293
- TParentRoute,
294
- TAllParams,
295
- TFullSearchSchema,
296
- TParentContext,
297
- TAllParentContext,
298
- TRouteContext
299
- >
300
- }
301
- : {
302
- getContext: GetContextFn<
303
- TParentRoute,
304
- TAllParams,
305
- TFullSearchSchema,
306
- TParentContext,
307
- TAllParentContext,
308
- TRouteContext
309
- >
310
- })
315
+ )
311
316
 
312
- type GetContextFn<
317
+ type BeforeLoadFn<
313
318
  TParentRoute,
314
319
  TAllParams,
320
+ TSearchSchema,
315
321
  TFullSearchSchema,
316
322
  TParentContext,
317
323
  TAllParentContext,
@@ -319,7 +325,10 @@ type GetContextFn<
319
325
  > = (
320
326
  opts: {
321
327
  params: TAllParams
328
+ routeSearch: TSearchSchema
322
329
  search: TFullSearchSchema
330
+ abortController: AbortController
331
+ preload: boolean
323
332
  } & (TParentRoute extends undefined
324
333
  ? {
325
334
  context?: TAllParentContext
@@ -329,7 +338,7 @@ type GetContextFn<
329
338
  context: TAllParentContext
330
339
  parentContext: TParentContext
331
340
  }),
332
- ) => TRouteContext
341
+ ) => Promise<TRouteContext> | TRouteContext | void
333
342
 
334
343
  export type UpdatableRouteOptions<
335
344
  TLoader,
@@ -378,19 +387,6 @@ export type UpdatableRouteOptions<
378
387
  maxAge?: number
379
388
  // If set, a match of this route that becomes inactive (or unused) will be garbage collected after this many milliseconds
380
389
  gcMaxAge?: number
381
- // This async function is called before a route is loaded.
382
- // If an error is thrown here, the route's loader will not be called.
383
- // If thrown during a navigation, the navigation will be cancelled and the error will be passed to the `onError` function.
384
- // If thrown during a preload event, the error will be logged to the console.
385
- beforeLoad?: (
386
- opts: LoaderContext<
387
- TSearchSchema,
388
- TFullSearchSchema,
389
- TAllParams,
390
- NoInfer<TRouteContext>,
391
- TAllContext
392
- >,
393
- ) => Promise<void> | void
394
390
  onError?: (err: any) => void
395
391
  // These functions are called as route matches are loaded, stick around and leave the active
396
392
  // matches
@@ -641,15 +637,7 @@ export class Route<
641
637
  TAllParentContext,
642
638
  TRouteContext,
643
639
  TAllContext
644
- > &
645
- UpdatableRouteOptions<
646
- TLoader,
647
- TSearchSchema,
648
- TFullSearchSchema,
649
- TAllParams,
650
- TRouteContext,
651
- TAllContext
652
- >
640
+ >
653
641
 
654
642
  // Set up in this.init()
655
643
  parentRoute!: TParentRoute
package/src/router.ts CHANGED
@@ -243,6 +243,7 @@ type LinkCurrentTargetElement = {
243
243
  }
244
244
 
245
245
  export interface DehydratedRouterState {
246
+ matchIds: string[]
246
247
  dehydratedMatches: DehydratedRouteMatch[]
247
248
  }
248
249
 
@@ -298,6 +299,7 @@ export type RouterListener<TRouterEvent extends RouterEvent> = {
298
299
 
299
300
  const visibilityChangeEvent = 'visibilitychange'
300
301
  const focusEvent = 'focus'
302
+ const preloadWarning = 'Error preloading route! ☝️'
301
303
 
302
304
  export class Router<
303
305
  TRouteTree extends AnyRoute = AnyRoute,
@@ -914,52 +916,24 @@ export class Router<
914
916
  }
915
917
  })()
916
918
 
917
- Object.assign(match, {
918
- ...searchInfo,
919
- })
920
-
921
- const contextInfo = (() => {
922
- try {
923
- const routeContext =
924
- route.options.getContext?.({
925
- parentContext: parentMatch?.routeContext ?? {},
926
- context: parentMatch?.context ?? this?.options.context ?? {},
927
- params: match.params,
928
- search: match.search,
929
- }) || ({} as any)
930
-
931
- const context = {
932
- ...(parentMatch?.context ?? this?.options.context),
933
- ...routeContext,
934
- } as any
935
-
936
- return {
937
- context,
938
- routeContext,
939
- }
940
- } catch (err) {
941
- route.options.onError?.(err)
942
- throw err
943
- }
944
- })()
945
-
946
- Object.assign(match, {
947
- ...contextInfo,
948
- })
919
+ Object.assign(match, searchInfo)
949
920
  })
950
921
 
951
922
  return matches as any
952
923
  }
953
924
 
954
925
  loadMatches = async (
955
- resolvedMatches: AnyRouteMatch[],
926
+ _resolvedMatches: AnyRouteMatch[],
956
927
  opts?: {
957
928
  preload?: boolean
958
929
  maxAge?: number
959
930
  },
960
931
  ) => {
932
+ const getFreshMatches = () =>
933
+ _resolvedMatches.map((d) => this.getRouteMatch(d.id)!)
934
+
961
935
  if (!opts?.preload) {
962
- resolvedMatches.forEach((match) => {
936
+ getFreshMatches().forEach((match) => {
963
937
  // Update each match with its latest route data
964
938
  this.setRouteMatch(match.id, (s) => ({
965
939
  ...s,
@@ -980,7 +954,8 @@ export class Router<
980
954
 
981
955
  // Check each match middleware to see if the route can be accessed
982
956
  try {
983
- for (const [index, match] of resolvedMatches.entries()) {
957
+ for (const [index, match] of getFreshMatches().entries()) {
958
+ const parentMatch = getFreshMatches()[index - 1]
984
959
  const route = this.getRoute(match.routeId)
985
960
 
986
961
  const handleError = (err: any, code: string) => {
@@ -1020,10 +995,24 @@ export class Router<
1020
995
  let didError = false
1021
996
 
1022
997
  try {
1023
- await route.options.beforeLoad?.({
1024
- ...match,
1025
- preload: !!opts?.preload,
1026
- })
998
+ const routeContext =
999
+ (await route.options.beforeLoad?.({
1000
+ ...match,
1001
+ preload: !!opts?.preload,
1002
+ parentContext: parentMatch?.routeContext ?? {},
1003
+ context: parentMatch?.context ?? this?.options.context ?? {},
1004
+ })) ?? ({} as any)
1005
+
1006
+ const context = {
1007
+ ...(parentMatch?.context ?? this?.options.context),
1008
+ ...routeContext,
1009
+ } as any
1010
+
1011
+ this.setRouteMatch(match.id, (s) => ({
1012
+ ...s,
1013
+ context,
1014
+ routeContext,
1015
+ }))
1027
1016
  } catch (err) {
1028
1017
  handleError(err, 'BEFORE_LOAD')
1029
1018
  didError = true
@@ -1042,7 +1031,7 @@ export class Router<
1042
1031
  throw err
1043
1032
  }
1044
1033
 
1045
- const validResolvedMatches = resolvedMatches.slice(0, firstBadMatchIndex)
1034
+ const validResolvedMatches = getFreshMatches().slice(0, firstBadMatchIndex)
1046
1035
  const matchPromises: Promise<any>[] = []
1047
1036
 
1048
1037
  validResolvedMatches.forEach((match, index) => {
@@ -1335,7 +1324,7 @@ export class Router<
1335
1324
  if (preload) {
1336
1325
  this.preloadRoute(nextOpts).catch((err) => {
1337
1326
  console.warn(err)
1338
- console.warn('Error preloading route! ☝️')
1327
+ console.warn(preloadWarning)
1339
1328
  })
1340
1329
  }
1341
1330
  }
@@ -1343,7 +1332,7 @@ export class Router<
1343
1332
  const handleTouchStart = (e: TouchEvent) => {
1344
1333
  this.preloadRoute(nextOpts).catch((err) => {
1345
1334
  console.warn(err)
1346
- console.warn('Error preloading route! ☝️')
1335
+ console.warn(preloadWarning)
1347
1336
  })
1348
1337
  }
1349
1338
 
@@ -1359,7 +1348,7 @@ export class Router<
1359
1348
  target.preloadTimeout = null
1360
1349
  this.preloadRoute(nextOpts).catch((err) => {
1361
1350
  console.warn(err)
1362
- console.warn('Error preloading route! ☝️')
1351
+ console.warn(preloadWarning)
1363
1352
  })
1364
1353
  }, preloadDelay)
1365
1354
  }
@@ -1390,6 +1379,7 @@ export class Router<
1390
1379
  dehydrate = (): DehydratedRouter => {
1391
1380
  return {
1392
1381
  state: {
1382
+ matchIds: this.state.matchIds,
1393
1383
  dehydratedMatches: this.state.matches.map((d) =>
1394
1384
  pick(d, [
1395
1385
  'fetchedAt',
@@ -1421,13 +1411,15 @@ export class Router<
1421
1411
  const ctx = _ctx
1422
1412
  this.dehydratedData = ctx.payload as any
1423
1413
  this.options.hydrate?.(ctx.payload as any)
1424
- const { dehydratedMatches } = ctx.router.state
1414
+ const dehydratedState = ctx.router.state
1425
1415
 
1426
1416
  let matches = this.matchRoutes(
1427
1417
  this.state.location.pathname,
1428
1418
  this.state.location.search,
1429
1419
  ).map((match) => {
1430
- const dehydratedMatch = dehydratedMatches.find((d) => d.id === match.id)
1420
+ const dehydratedMatch = dehydratedState.dehydratedMatches.find(
1421
+ (d) => d.id === match.id,
1422
+ )
1431
1423
 
1432
1424
  invariant(
1433
1425
  dehydratedMatch,
@@ -1446,6 +1438,7 @@ export class Router<
1446
1438
  this.__store.setState((s) => {
1447
1439
  return {
1448
1440
  ...s,
1441
+ matchIds: dehydratedState.matchIds,
1449
1442
  matches,
1450
1443
  matchesById: this.#mergeMatches(s.matchesById, matches),
1451
1444
  }
@@ -1469,10 +1462,10 @@ export class Router<
1469
1462
  return `<script id='${id}' suppressHydrationWarning>window["__TSR_DEHYDRATED__${escapeJSON(
1470
1463
  strKey,
1471
1464
  )}"] = ${JSON.stringify(data)}
1472
- // ;(() => {
1473
- // var el = document.getElementById('${id}')
1474
- // el.parentElement.removeChild(el)
1475
- // })()
1465
+ ;(() => {
1466
+ var el = document.getElementById('${id}')
1467
+ el.parentElement.removeChild(el)
1468
+ })()
1476
1469
  </script>`
1477
1470
  })
1478
1471