@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.
@@ -58,11 +58,14 @@ export type AnyRouteProps = RegisteredRouteProps<any, any, any, any, any>;
58
58
  export type RouteOptions<TParentRoute extends AnyRoute = AnyRoute, TCustomId extends string = string, TPath extends string = string, TLoader = unknown, TParentSearchSchema extends AnySearchSchema = {}, TSearchSchema extends AnySearchSchema = {}, TFullSearchSchema extends AnySearchSchema = TSearchSchema, TParams extends AnyPathParams = AnyPathParams, TAllParams extends AnyPathParams = TParams, TParentContext extends AnyContext = AnyContext, TAllParentContext extends AnyContext = AnyContext, TRouteContext extends RouteContext = RouteContext, TAllContext extends AnyContext = AnyContext> = BaseRouteOptions<TParentRoute, TCustomId, TPath, TLoader, TParentSearchSchema, TSearchSchema, TFullSearchSchema, TParams, TAllParams, TParentContext, TAllParentContext, TRouteContext, TAllContext> & UpdatableRouteOptions<TLoader, TSearchSchema, TFullSearchSchema, TAllParams, TRouteContext, TAllContext>;
59
59
  export type ParamsFallback<TPath extends string, TParams> = unknown extends TParams ? Record<ParsePathParams<TPath>, string> : TParams;
60
60
  export type BaseRouteOptions<TParentRoute extends AnyRoute = AnyRoute, TCustomId extends string = string, TPath extends string = string, TLoader = unknown, TParentSearchSchema extends AnySearchSchema = {}, TSearchSchema extends AnySearchSchema = {}, TFullSearchSchema extends AnySearchSchema = TSearchSchema, TParams extends AnyPathParams = {}, TAllParams = ParamsFallback<TPath, TParams>, TParentContext extends AnyContext = AnyContext, TAllParentContext extends AnyContext = AnyContext, TRouteContext extends RouteContext = RouteContext, TAllContext extends AnyContext = AnyContext> = RoutePathOptions<TCustomId, TPath> & {
61
- layoutLimit?: string;
62
61
  getParentRoute: () => TParentRoute;
63
62
  validateSearch?: SearchSchemaValidator<TSearchSchema>;
64
63
  loader?: LoaderFn<TLoader, TSearchSchema, TFullSearchSchema, TAllParams, NoInfer<TRouteContext>, TAllContext>;
65
- } & ([TLoader] extends [never] ? {
64
+ } & (keyof PickRequired<RouteContext> extends never ? {
65
+ beforeLoad?: BeforeLoadFn<TParentRoute, TAllParams, TSearchSchema, TFullSearchSchema, TParentContext, TAllParentContext, TRouteContext>;
66
+ } : {
67
+ beforeLoad: BeforeLoadFn<TParentRoute, TAllParams, TSearchSchema, TFullSearchSchema, TParentContext, TAllParentContext, TRouteContext>;
68
+ }) & ([TLoader] extends [never] ? {
66
69
  loader: 'Loaders must return a type other than never. If you are throwing a redirect() and not returning anything, return a redirect() instead.';
67
70
  } : {}) & ({
68
71
  parseParams?: (rawParams: IsAny<TPath, any, Record<ParsePathParams<TPath>, string>>) => TParams extends Record<ParsePathParams<TPath>, any> ? TParams : 'parseParams must return an object';
@@ -70,21 +73,20 @@ export type BaseRouteOptions<TParentRoute extends AnyRoute = AnyRoute, TCustomId
70
73
  } | {
71
74
  stringifyParams?: never;
72
75
  parseParams?: never;
73
- }) & (keyof PickRequired<RouteContext> extends never ? {
74
- getContext?: GetContextFn<TParentRoute, TAllParams, TFullSearchSchema, TParentContext, TAllParentContext, TRouteContext>;
75
- } : {
76
- getContext: GetContextFn<TParentRoute, TAllParams, TFullSearchSchema, TParentContext, TAllParentContext, TRouteContext>;
77
76
  });
78
- type GetContextFn<TParentRoute, TAllParams, TFullSearchSchema, TParentContext, TAllParentContext, TRouteContext> = (opts: {
77
+ type BeforeLoadFn<TParentRoute, TAllParams, TSearchSchema, TFullSearchSchema, TParentContext, TAllParentContext, TRouteContext> = (opts: {
79
78
  params: TAllParams;
79
+ routeSearch: TSearchSchema;
80
80
  search: TFullSearchSchema;
81
+ abortController: AbortController;
82
+ preload: boolean;
81
83
  } & (TParentRoute extends undefined ? {
82
84
  context?: TAllParentContext;
83
85
  parentContext?: TParentContext;
84
86
  } : {
85
87
  context: TAllParentContext;
86
88
  parentContext: TParentContext;
87
- })) => TRouteContext;
89
+ })) => Promise<TRouteContext> | TRouteContext | void;
88
90
  export type UpdatableRouteOptions<TLoader, TSearchSchema extends AnySearchSchema, TFullSearchSchema extends AnySearchSchema, TAllParams extends AnyPathParams, TRouteContext extends AnyContext, TAllContext extends AnyContext> = MetaOptions & {
89
91
  key?: null | false | GetKeyFn<TFullSearchSchema, TAllParams>;
90
92
  caseSensitive?: boolean;
@@ -97,7 +99,6 @@ export type UpdatableRouteOptions<TLoader, TSearchSchema extends AnySearchSchema
97
99
  preloadMaxAge?: number;
98
100
  maxAge?: number;
99
101
  gcMaxAge?: number;
100
- beforeLoad?: (opts: LoaderContext<TSearchSchema, TFullSearchSchema, TAllParams, NoInfer<TRouteContext>, TAllContext>) => Promise<void> | void;
101
102
  onError?: (err: any) => void;
102
103
  onEnter?: (match: AnyRouteMatch) => void;
103
104
  onTransition?: (match: AnyRouteMatch) => void;
@@ -199,7 +200,7 @@ export declare class Route<TParentRoute extends RouteConstraints['TParentRoute']
199
200
  routerContext: TRouterContext;
200
201
  };
201
202
  isRoot: TParentRoute extends Route<any> ? true : false;
202
- options: RouteOptions<TParentRoute, TCustomId, TPath, TLoader, InferFullSearchSchema<TParentRoute>, TSearchSchema, TFullSearchSchema, TParams, TAllParams, TParentContext, TAllParentContext, TRouteContext, TAllContext> & UpdatableRouteOptions<TLoader, TSearchSchema, TFullSearchSchema, TAllParams, TRouteContext, TAllContext>;
203
+ options: RouteOptions<TParentRoute, TCustomId, TPath, TLoader, InferFullSearchSchema<TParentRoute>, TSearchSchema, TFullSearchSchema, TParams, TAllParams, TParentContext, TAllParentContext, TRouteContext, TAllContext>;
203
204
  parentRoute: TParentRoute;
204
205
  id: TId;
205
206
  path: TPath;
@@ -136,6 +136,7 @@ export interface MatchRouteOptions {
136
136
  fuzzy?: boolean;
137
137
  }
138
138
  export interface DehydratedRouterState {
139
+ matchIds: string[];
139
140
  dehydratedMatches: DehydratedRouteMatch[];
140
141
  }
141
142
  export type DehydratedRouteMatch = Pick<RouteMatch, 'fetchedAt' | 'invalid' | 'maxAge' | 'preloadMaxAge' | 'id' | 'loaderData' | 'status' | 'updatedAt'>;
@@ -209,7 +210,7 @@ export declare class Router<TRouteTree extends AnyRoute = AnyRoute, TDehydrated
209
210
  throwOnError?: boolean;
210
211
  debug?: boolean;
211
212
  }) => RouteMatch<TRouteTree>[];
212
- loadMatches: (resolvedMatches: AnyRouteMatch[], opts?: {
213
+ loadMatches: (_resolvedMatches: AnyRouteMatch[], opts?: {
213
214
  preload?: boolean;
214
215
  maxAge?: number;
215
216
  }) => Promise<void>;
@@ -806,6 +806,7 @@
806
806
  const componentTypes = ['component', 'errorComponent', 'pendingComponent'];
807
807
  const visibilityChangeEvent = 'visibilitychange';
808
808
  const focusEvent = 'focus';
809
+ const preloadWarning = 'Error preloading route! ☝️';
809
810
  class Router {
810
811
  #unsubHistory;
811
812
  resetNextScroll = false;
@@ -1235,39 +1236,14 @@
1235
1236
  return parentSearchInfo;
1236
1237
  }
1237
1238
  })();
1238
- Object.assign(match, {
1239
- ...searchInfo
1240
- });
1241
- const contextInfo = (() => {
1242
- try {
1243
- const routeContext = route.options.getContext?.({
1244
- parentContext: parentMatch?.routeContext ?? {},
1245
- context: parentMatch?.context ?? this?.options.context ?? {},
1246
- params: match.params,
1247
- search: match.search
1248
- }) || {};
1249
- const context = {
1250
- ...(parentMatch?.context ?? this?.options.context),
1251
- ...routeContext
1252
- };
1253
- return {
1254
- context,
1255
- routeContext
1256
- };
1257
- } catch (err) {
1258
- route.options.onError?.(err);
1259
- throw err;
1260
- }
1261
- })();
1262
- Object.assign(match, {
1263
- ...contextInfo
1264
- });
1239
+ Object.assign(match, searchInfo);
1265
1240
  });
1266
1241
  return matches;
1267
1242
  };
1268
- loadMatches = async (resolvedMatches, opts) => {
1243
+ loadMatches = async (_resolvedMatches, opts) => {
1244
+ const getFreshMatches = () => _resolvedMatches.map(d => this.getRouteMatch(d.id));
1269
1245
  if (!opts?.preload) {
1270
- resolvedMatches.forEach(match => {
1246
+ getFreshMatches().forEach(match => {
1271
1247
  // Update each match with its latest route data
1272
1248
  this.setRouteMatch(match.id, s => ({
1273
1249
  ...s,
@@ -1287,7 +1263,8 @@
1287
1263
 
1288
1264
  // Check each match middleware to see if the route can be accessed
1289
1265
  try {
1290
- for (const [index, match] of resolvedMatches.entries()) {
1266
+ for (const [index, match] of getFreshMatches().entries()) {
1267
+ const parentMatch = getFreshMatches()[index - 1];
1291
1268
  const route = this.getRoute(match.routeId);
1292
1269
  const handleError = (err, code) => {
1293
1270
  err.routerCode = code;
@@ -1318,10 +1295,21 @@
1318
1295
  }
1319
1296
  let didError = false;
1320
1297
  try {
1321
- await route.options.beforeLoad?.({
1298
+ const routeContext = (await route.options.beforeLoad?.({
1322
1299
  ...match,
1323
- preload: !!opts?.preload
1324
- });
1300
+ preload: !!opts?.preload,
1301
+ parentContext: parentMatch?.routeContext ?? {},
1302
+ context: parentMatch?.context ?? this?.options.context ?? {}
1303
+ })) ?? {};
1304
+ const context = {
1305
+ ...(parentMatch?.context ?? this?.options.context),
1306
+ ...routeContext
1307
+ };
1308
+ this.setRouteMatch(match.id, s => ({
1309
+ ...s,
1310
+ context,
1311
+ routeContext
1312
+ }));
1325
1313
  } catch (err) {
1326
1314
  handleError(err, 'BEFORE_LOAD');
1327
1315
  didError = true;
@@ -1338,7 +1326,7 @@
1338
1326
  }
1339
1327
  throw err;
1340
1328
  }
1341
- const validResolvedMatches = resolvedMatches.slice(0, firstBadMatchIndex);
1329
+ const validResolvedMatches = getFreshMatches().slice(0, firstBadMatchIndex);
1342
1330
  const matchPromises = [];
1343
1331
  validResolvedMatches.forEach((match, index) => {
1344
1332
  matchPromises.push((async () => {
@@ -1547,14 +1535,14 @@
1547
1535
  if (preload) {
1548
1536
  this.preloadRoute(nextOpts).catch(err => {
1549
1537
  console.warn(err);
1550
- console.warn('Error preloading route! ☝️');
1538
+ console.warn(preloadWarning);
1551
1539
  });
1552
1540
  }
1553
1541
  };
1554
1542
  const handleTouchStart = e => {
1555
1543
  this.preloadRoute(nextOpts).catch(err => {
1556
1544
  console.warn(err);
1557
- console.warn('Error preloading route! ☝️');
1545
+ console.warn(preloadWarning);
1558
1546
  });
1559
1547
  };
1560
1548
  const handleEnter = e => {
@@ -1567,7 +1555,7 @@
1567
1555
  target.preloadTimeout = null;
1568
1556
  this.preloadRoute(nextOpts).catch(err => {
1569
1557
  console.warn(err);
1570
- console.warn('Error preloading route! ☝️');
1558
+ console.warn(preloadWarning);
1571
1559
  });
1572
1560
  }, preloadDelay);
1573
1561
  }
@@ -1594,6 +1582,7 @@
1594
1582
  dehydrate = () => {
1595
1583
  return {
1596
1584
  state: {
1585
+ matchIds: this.state.matchIds,
1597
1586
  dehydratedMatches: this.state.matches.map(d => pick(d, ['fetchedAt', 'invalid', 'preloadMaxAge', 'maxAge', 'id', 'loaderData', 'status', 'updatedAt']))
1598
1587
  }
1599
1588
  };
@@ -1608,11 +1597,9 @@
1608
1597
  const ctx = _ctx;
1609
1598
  this.dehydratedData = ctx.payload;
1610
1599
  this.options.hydrate?.(ctx.payload);
1611
- const {
1612
- dehydratedMatches
1613
- } = ctx.router.state;
1600
+ const dehydratedState = ctx.router.state;
1614
1601
  let matches = this.matchRoutes(this.state.location.pathname, this.state.location.search).map(match => {
1615
- const dehydratedMatch = dehydratedMatches.find(d => d.id === match.id);
1602
+ const dehydratedMatch = dehydratedState.dehydratedMatches.find(d => d.id === match.id);
1616
1603
  invariant(dehydratedMatch, `Could not find a client-side match for dehydrated match with id: ${match.id}!`);
1617
1604
  if (dehydratedMatch) {
1618
1605
  return {
@@ -1625,6 +1612,7 @@
1625
1612
  this.__store.setState(s => {
1626
1613
  return {
1627
1614
  ...s,
1615
+ matchIds: dehydratedState.matchIds,
1628
1616
  matches,
1629
1617
  matchesById: this.#mergeMatches(s.matchesById, matches)
1630
1618
  };
@@ -1641,10 +1629,10 @@
1641
1629
  const id = `__TSR_DEHYDRATED__${strKey}`;
1642
1630
  const data = typeof getData === 'function' ? await getData() : getData;
1643
1631
  return `<script id='${id}' suppressHydrationWarning>window["__TSR_DEHYDRATED__${escapeJSON(strKey)}"] = ${JSON.stringify(data)}
1644
- // ;(() => {
1645
- // var el = document.getElementById('${id}')
1646
- // el.parentElement.removeChild(el)
1647
- // })()
1632
+ ;(() => {
1633
+ var el = document.getElementById('${id}')
1634
+ el.parentElement.removeChild(el)
1635
+ })()
1648
1636
  </script>`;
1649
1637
  });
1650
1638
  return () => this.hydrateData(key);