@tanstack/router-core 0.0.1-alpha.9 → 0.0.1-beta.10

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-alpha.9",
4
+ "version": "0.0.1-beta.10",
5
5
  "license": "MIT",
6
6
  "repository": "tanstack/router",
7
7
  "homepage": "https://tanstack.com/router",
package/src/frameworks.ts CHANGED
@@ -4,7 +4,6 @@ export interface FrameworkGenerics {
4
4
  // pre-defined as constraints:
5
5
  //
6
6
  // Element: any
7
- // AsyncElement: any
8
7
  // SyncOrAsyncElement?: any
9
8
  }
10
9
 
package/src/link.ts CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  RouteInfoByPath,
6
6
  } from './routeInfo'
7
7
  import { Location } from './router'
8
- import { NoInfer, PickAsRequired, PickRequired, Updater } from './utils'
8
+ import { Expand, NoInfer, PickAsRequired, PickRequired, Updater } from './utils'
9
9
 
10
10
  export type LinkInfo =
11
11
  | {
@@ -35,23 +35,25 @@ type CleanPath<T extends string> = T extends `${infer L}//${infer R}`
35
35
  ? `/${CleanPath<L>}`
36
36
  : T
37
37
 
38
- export type Split<S, TTrailing = true> = S extends unknown
38
+ export type Split<S, TIncludeTrailingSlash = true> = S extends unknown
39
39
  ? string extends S
40
40
  ? string[]
41
41
  : S extends string
42
42
  ? CleanPath<S> extends ''
43
43
  ? []
44
- : TTrailing extends true
44
+ : TIncludeTrailingSlash extends true
45
45
  ? CleanPath<S> extends `${infer T}/`
46
- ? [T, '/']
46
+ ? [...Split<T>, '/']
47
47
  : CleanPath<S> extends `/${infer U}`
48
- ? ['/', U]
48
+ ? Split<U>
49
49
  : CleanPath<S> extends `${infer T}/${infer U}`
50
- ? [T, ...Split<U>]
50
+ ? [...Split<T>, ...Split<U>]
51
51
  : [S]
52
52
  : CleanPath<S> extends `${infer T}/${infer U}`
53
- ? [T, ...Split<U>]
54
- : [S]
53
+ ? [...Split<T>, ...Split<U>]
54
+ : S extends string
55
+ ? [S]
56
+ : never
55
57
  : never
56
58
  : never
57
59
 
@@ -128,7 +130,7 @@ export type ToOptions<
128
130
  from?: TFrom
129
131
  // // When using relative route paths, this option forces resolution from the current path, instead of the route API's path or `from` path
130
132
  // fromCurrent?: boolean
131
- } & CheckPath<TAllRouteInfo, NoInfer<TResolvedTo>> &
133
+ } & CheckPath<TAllRouteInfo, NoInfer<TResolvedTo>, {}> &
132
134
  SearchParamOptions<TAllRouteInfo, TFrom, TResolvedTo> &
133
135
  PathParamOptions<TAllRouteInfo, TFrom, TResolvedTo>
134
136
 
@@ -248,19 +250,41 @@ export type CheckRelativePath<
248
250
  : {}
249
251
  : {}
250
252
 
251
- export type CheckPath<TAllRouteInfo extends AnyAllRouteInfo, TPath> = Exclude<
253
+ export type CheckPath<
254
+ TAllRouteInfo extends AnyAllRouteInfo,
252
255
  TPath,
253
- TAllRouteInfo['routePaths']
254
- > extends never
255
- ? {}
256
+ TPass,
257
+ > = Exclude<TPath, TAllRouteInfo['routePaths']> extends never
258
+ ? TPass
256
259
  : CheckPathError<TAllRouteInfo, Exclude<TPath, TAllRouteInfo['routePaths']>>
257
260
 
258
- export type CheckPathError<TAllRouteInfo extends AnyAllRouteInfo, TInvalids> = {
261
+ export type CheckPathError<
262
+ TAllRouteInfo extends AnyAllRouteInfo,
263
+ TInvalids,
264
+ > = Expand<{
259
265
  Error: `${TInvalids extends string
260
266
  ? TInvalids
261
267
  : never} is not a valid route path.`
262
268
  'Valid Route Paths': TAllRouteInfo['routePaths']
263
- }
269
+ }>
270
+
271
+ export type CheckId<
272
+ TAllRouteInfo extends AnyAllRouteInfo,
273
+ TPath,
274
+ TPass,
275
+ > = Exclude<TPath, TAllRouteInfo['routeIds']> extends never
276
+ ? TPass
277
+ : CheckIdError<TAllRouteInfo, Exclude<TPath, TAllRouteInfo['routeIds']>>
278
+
279
+ export type CheckIdError<
280
+ TAllRouteInfo extends AnyAllRouteInfo,
281
+ TInvalids,
282
+ > = Expand<{
283
+ Error: `${TInvalids extends string
284
+ ? TInvalids
285
+ : never} is not a valid route ID.`
286
+ 'Valid Route IDs': TAllRouteInfo['routeIds']
287
+ }>
264
288
 
265
289
  export type ResolveRelativePath<TFrom, TTo = '.'> = TFrom extends string
266
290
  ? TTo extends string
@@ -274,10 +298,14 @@ export type ResolveRelativePath<TFrom, TTo = '.'> = TFrom extends string
274
298
  ? TTo
275
299
  : Split<TTo> extends ['..', ...infer ToRest]
276
300
  ? Split<TFrom> extends [...infer FromRest, infer FromTail]
277
- ? ResolveRelativePath<Join<FromRest>, Join<ToRest>>
301
+ ? ToRest extends ['/']
302
+ ? Join<[...FromRest, '/']>
303
+ : ResolveRelativePath<Join<FromRest>, Join<ToRest>>
278
304
  : never
279
305
  : Split<TTo> extends ['.', ...infer ToRest]
280
- ? ResolveRelativePath<TFrom, Join<ToRest>>
306
+ ? ToRest extends ['/']
307
+ ? Join<[TFrom, '/']>
308
+ : ResolveRelativePath<TFrom, Join<ToRest>>
281
309
  : CleanPath<Join<['/', ...Split<TFrom>, ...Split<TTo>]>>
282
310
  : never
283
311
  : never
package/src/qss.ts CHANGED
@@ -30,6 +30,7 @@ function toValue(mix) {
30
30
  var str = decodeURIComponent(mix)
31
31
  if (str === 'false') return false
32
32
  if (str === 'true') return true
33
+ if (str.charAt(0) === '0') return str
33
34
  return +str * 0 === 0 ? +str : str
34
35
  }
35
36
 
package/src/route.ts CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  ResolveRelativePath,
6
6
  ToOptions,
7
7
  } from './link'
8
- import { RouteConfig, RouteOptions } from './routeConfig'
8
+ import { LoaderContext, RouteConfig, RouteOptions } from './routeConfig'
9
9
  import {
10
10
  AnyAllRouteInfo,
11
11
  AnyRouteInfo,
@@ -13,9 +13,15 @@ import {
13
13
  RouteInfo,
14
14
  RouteInfoByPath,
15
15
  } from './routeInfo'
16
- import { RouteMatch } from './routeMatch'
17
- import { Action, ActionState, MatchRouteOptions, Router } from './router'
18
- import { NoInfer, replaceEqualDeep } from './utils'
16
+ import {
17
+ Action,
18
+ ActionState,
19
+ Loader,
20
+ LoaderState,
21
+ MatchRouteOptions,
22
+ Router,
23
+ } from './router'
24
+ import { NoInfer } from './utils'
19
25
 
20
26
  export interface AnyRoute extends Route<any, any> {}
21
27
 
@@ -57,6 +63,21 @@ export interface Route<
57
63
  | Action<TRouteInfo['actionPayload'], TRouteInfo['actionResponse']>
58
64
  | undefined
59
65
  : Action<TRouteInfo['actionPayload'], TRouteInfo['actionResponse']>
66
+ loader: unknown extends TRouteInfo['routeLoaderData']
67
+ ?
68
+ | Action<
69
+ LoaderContext<
70
+ TRouteInfo['fullSearchSchema'],
71
+ TRouteInfo['allParams']
72
+ >,
73
+ TRouteInfo['routeLoaderData']
74
+ >
75
+ | undefined
76
+ : Loader<
77
+ TRouteInfo['fullSearchSchema'],
78
+ TRouteInfo['allParams'],
79
+ TRouteInfo['routeLoaderData']
80
+ >
60
81
  }
61
82
 
62
83
  export function createRoute<
@@ -74,10 +95,10 @@ export function createRoute<
74
95
  router.state.actions[id] ||
75
96
  (() => {
76
97
  router.state.actions[id] = {
77
- pending: [],
98
+ submissions: [],
78
99
  submit: async <T, U>(
79
100
  submission: T,
80
- actionOpts?: { invalidate?: boolean },
101
+ actionOpts?: { invalidate?: boolean; multi?: boolean },
81
102
  ) => {
82
103
  if (!route) {
83
104
  return
@@ -85,27 +106,27 @@ export function createRoute<
85
106
 
86
107
  const invalidate = actionOpts?.invalidate ?? true
87
108
 
109
+ if (!actionOpts?.multi) {
110
+ action.submissions = action.submissions.filter((d) => d.isMulti)
111
+ }
112
+
88
113
  const actionState: ActionState<T, U> = {
89
114
  submittedAt: Date.now(),
90
115
  status: 'pending',
91
116
  submission,
117
+ isMulti: !!actionOpts?.multi,
92
118
  }
93
119
 
94
120
  action.current = actionState
95
121
  action.latest = actionState
96
- action.pending.push(actionState)
97
-
98
- router.state = {
99
- ...router.state,
100
- currentAction: actionState,
101
- latestAction: actionState,
102
- }
122
+ action.submissions.push(actionState)
103
123
 
104
124
  router.notify()
105
125
 
106
126
  try {
107
127
  const res = await route.options.action?.(submission)
108
128
  actionState.data = res as U
129
+
109
130
  if (invalidate) {
110
131
  router.invalidateRoute({ to: '.', fromCurrent: true })
111
132
  await router.reload()
@@ -117,8 +138,6 @@ export function createRoute<
117
138
  actionState.error = err
118
139
  actionState.status = 'error'
119
140
  } finally {
120
- action.pending = action.pending.filter((d) => d !== actionState)
121
- router.removeActionQueue.push({ action, actionState })
122
141
  router.notify()
123
142
  }
124
143
  },
@@ -126,6 +145,45 @@ export function createRoute<
126
145
  return router.state.actions[id]!
127
146
  })()
128
147
 
148
+ const loader =
149
+ router.state.loaders[id] ||
150
+ (() => {
151
+ router.state.loaders[id] = {
152
+ pending: [],
153
+ fetch: (async (loaderContext: LoaderContext<any, any>) => {
154
+ if (!route) {
155
+ return
156
+ }
157
+
158
+ const loaderState: LoaderState<any, any> = {
159
+ loadedAt: Date.now(),
160
+ loaderContext,
161
+ }
162
+
163
+ loader.current = loaderState
164
+ loader.latest = loaderState
165
+ loader.pending.push(loaderState)
166
+
167
+ // router.state = {
168
+ // ...router.state,
169
+ // currentAction: loaderState,
170
+ // latestAction: loaderState,
171
+ // }
172
+
173
+ router.notify()
174
+
175
+ try {
176
+ return await route.options.loader?.(loaderContext)
177
+ } finally {
178
+ loader.pending = loader.pending.filter((d) => d !== loaderState)
179
+ // router.removeActionQueue.push({ loader, loaderState })
180
+ router.notify()
181
+ }
182
+ }) as any,
183
+ }
184
+ return router.state.loaders[id]!
185
+ })()
186
+
129
187
  let route: Route<TAllRouteInfo, TRouteInfo> = {
130
188
  routeId: id,
131
189
  routeRouteId: routeId,
@@ -136,6 +194,7 @@ export function createRoute<
136
194
  childRoutes: undefined!,
137
195
  parentRoute: parent,
138
196
  action,
197
+ loader: loader as any,
139
198
 
140
199
  buildLink: (options) => {
141
200
  return router.buildLink({
@@ -166,16 +225,3 @@ export function createRoute<
166
225
 
167
226
  return route
168
227
  }
169
-
170
- export function cascadeLoaderData(matches: RouteMatch<any, any>[]) {
171
- matches.forEach((match, index) => {
172
- const parent = matches[index - 1]
173
-
174
- if (parent) {
175
- match.loaderData = replaceEqualDeep(match.loaderData, {
176
- ...parent.loaderData,
177
- ...match.routeLoaderData,
178
- })
179
- }
180
- })
181
- }
@@ -53,11 +53,18 @@ export type LoaderFn<
53
53
  TRouteLoaderData extends AnyLoaderData,
54
54
  TFullSearchSchema extends AnySearchSchema = {},
55
55
  TAllParams extends AnyPathParams = {},
56
- > = (loaderContext: {
56
+ > = (
57
+ loaderContext: LoaderContext<TFullSearchSchema, TAllParams>,
58
+ ) => Promise<TRouteLoaderData>
59
+
60
+ export interface LoaderContext<
61
+ TFullSearchSchema extends AnySearchSchema = {},
62
+ TAllParams extends AnyPathParams = {},
63
+ > {
57
64
  params: TAllParams
58
65
  search: TFullSearchSchema
59
66
  signal?: AbortSignal
60
- }) => Promise<TRouteLoaderData>
67
+ }
61
68
 
62
69
  export type ActionFn<TActionPayload = unknown, TActionResponse = unknown> = (
63
70
  submission: TActionPayload,
@@ -105,58 +112,6 @@ export type RouteOptions<
105
112
  pendingMs?: number
106
113
  // _If the `pendingElement` is shown_, the minimum duration for which it will be visible.
107
114
  pendingMinMs?: number
108
- // // An array of child routes
109
- // children?: Route<any, any, any, any>[]
110
- } & (
111
- | {
112
- parseParams?: never
113
- stringifyParams?: never
114
- }
115
- | {
116
- // Parse params optionally receives path params as strings and returns them in a parsed format (like a number or boolean)
117
- parseParams: (
118
- rawParams: IsAny<TPath, any, Record<ParsePathParams<TPath>, string>>,
119
- ) => TParams
120
- stringifyParams: (
121
- params: TParams,
122
- ) => Record<ParsePathParams<TPath>, string>
123
- }
124
- ) &
125
- RouteLoaders<
126
- // Route Loaders (see below) can be inline on the route, or resolved async
127
- TRouteLoaderData,
128
- TLoaderData,
129
- TActionPayload,
130
- TActionResponse,
131
- TFullSearchSchema,
132
- TAllParams
133
- > & {
134
- // If `import` is defined, this route can resolve its elements and loaders in a single asynchronous call
135
- // This is particularly useful for code-splitting or module federation
136
- import?: (opts: {
137
- params: AnyPathParams
138
- }) => Promise<
139
- RouteLoaders<
140
- TRouteLoaderData,
141
- TLoaderData,
142
- TActionPayload,
143
- TActionResponse,
144
- TFullSearchSchema,
145
- TAllParams
146
- >
147
- >
148
- } & (PickUnsafe<TParentParams, ParsePathParams<TPath>> extends never // Detect if an existing path param is being redefined
149
- ? {}
150
- : 'Cannot redefined path params in child routes!')
151
-
152
- export interface RouteLoaders<
153
- TRouteLoaderData extends AnyLoaderData = {},
154
- TLoaderData extends AnyLoaderData = {},
155
- TActionPayload = unknown,
156
- TActionResponse = unknown,
157
- TFullSearchSchema extends AnySearchSchema = {},
158
- TAllParams extends AnyPathParams = {},
159
- > {
160
115
  // The content to be rendered when the route is matched. If no element is provided, defaults to `<Outlet />`
161
116
  element?: GetFrameworkGeneric<'SyncOrAsyncElement'> // , NoInfer<TLoaderData>>
162
117
  // The content to be rendered when `loader` encounters an error
@@ -196,7 +151,24 @@ export interface RouteLoaders<
196
151
  }) => void
197
152
  // An object of whatever you want! This object is accessible anywhere matches are.
198
153
  meta?: RouteMeta // TODO: Make this nested and mergeable
199
- }
154
+ } & (
155
+ | {
156
+ parseParams?: never
157
+ stringifyParams?: never
158
+ }
159
+ | {
160
+ // Parse params optionally receives path params as strings and returns them in a parsed format (like a number or boolean)
161
+ parseParams: (
162
+ rawParams: IsAny<TPath, any, Record<ParsePathParams<TPath>, string>>,
163
+ ) => TParams
164
+ stringifyParams: (
165
+ params: TParams,
166
+ ) => Record<ParsePathParams<TPath>, string>
167
+ }
168
+ ) &
169
+ (PickUnsafe<TParentParams, ParsePathParams<TPath>> extends never // Detect if an existing path param is being redefined
170
+ ? {}
171
+ : 'Cannot redefined path params in child routes!')
200
172
 
201
173
  export type SearchFilter<T, U = T> = (prev: T) => U
202
174
 
package/src/routeMatch.ts CHANGED
@@ -1,13 +1,12 @@
1
1
  import { GetFrameworkGeneric } from './frameworks'
2
2
  import { Route } from './route'
3
- import { AnyPathParams } from './routeConfig'
4
3
  import {
5
4
  AnyAllRouteInfo,
6
5
  AnyRouteInfo,
7
6
  DefaultAllRouteInfo,
8
7
  RouteInfo,
9
8
  } from './routeInfo'
10
- import { Router } from './router'
9
+ import { ActionState, Router } from './router'
11
10
  import { replaceEqualDeep, Timeout } from './utils'
12
11
 
13
12
  export interface RouteMatch<
@@ -16,7 +15,7 @@ export interface RouteMatch<
16
15
  > extends Route<TAllRouteInfo, TRouteInfo> {
17
16
  matchId: string
18
17
  pathname: string
19
- params: AnyPathParams
18
+ params: TRouteInfo['params']
20
19
  parentMatch?: RouteMatch
21
20
  childMatches: RouteMatch[]
22
21
  routeSearch: TRouteInfo['searchSchema']
@@ -37,8 +36,7 @@ export interface RouteMatch<
37
36
  catchElement?: GetFrameworkGeneric<'Element'> // , TRouteInfo['loaderData']>
38
37
  pendingElement?: GetFrameworkGeneric<'Element'> // , TRouteInfo['loaderData']>
39
38
  loadPromise?: Promise<void>
40
- loaderPromise?: Promise<void>
41
- importPromise?: Promise<void>
39
+ loaderDataPromise?: Promise<void>
42
40
  elementsPromise?: Promise<void>
43
41
  dataPromise?: Promise<void>
44
42
  pendingTimeout?: Timeout
@@ -61,7 +59,13 @@ export interface RouteMatch<
61
59
  resolve: () => void
62
60
  }
63
61
  cancel: () => void
64
- load: (opts?: { maxAge?: number }) => Promise<void>
62
+ load: (
63
+ loaderOpts?: { withPending?: boolean } & (
64
+ | { preload: true; maxAge: number; gcMaxAge: number }
65
+ | { preload?: false; maxAge?: never; gcMaxAge?: never }
66
+ ),
67
+ ) => Promise<TRouteInfo['routeLoaderData']>
68
+ fetch: (opts?: { maxAge?: number }) => Promise<TRouteInfo['routeLoaderData']>
65
69
  invalidate: () => void
66
70
  hasLoaders: () => boolean
67
71
  }
@@ -99,6 +103,7 @@ export function createRouteMatch<
99
103
  isFetching: false,
100
104
  isInvalid: false,
101
105
  invalidAt: Infinity,
106
+ // pendingActions: [],
102
107
  getIsInvalid: () => {
103
108
  const now = Date.now()
104
109
  return routeMatch.isInvalid || routeMatch.invalidAt < now
@@ -142,18 +147,6 @@ export function createRouteMatch<
142
147
  clearTimeout(routeMatch.__.pendingMinTimeout)
143
148
  delete routeMatch.__.pendingMinPromise
144
149
  },
145
- // setParentMatch: (parentMatch?: RouteMatch) => {
146
- // routeMatch.parentMatch = parentMatch
147
- // },
148
- // addChildMatch: (childMatch: RouteMatch) => {
149
- // if (
150
- // routeMatch.childMatches.find((d) => d.matchId === childMatch.matchId)
151
- // ) {
152
- // return
153
- // }
154
-
155
- // routeMatch.childMatches.push(childMatch)
156
- // },
157
150
  validate: () => {
158
151
  // Validate the search params and stabilize them
159
152
  const parentSearch =
@@ -169,7 +162,7 @@ export function createRouteMatch<
169
162
 
170
163
  let nextSearch = replaceEqualDeep(
171
164
  prevSearch,
172
- validator?.(parentSearch),
165
+ validator?.(parentSearch) ?? {},
173
166
  )
174
167
 
175
168
  // Invalidate route matches when search param stability changes
@@ -183,6 +176,14 @@ export function createRouteMatch<
183
176
  ...parentSearch,
184
177
  ...nextSearch,
185
178
  })
179
+
180
+ elementTypes.map(async (type) => {
181
+ const routeElement = routeMatch.options[type]
182
+
183
+ if (typeof routeMatch.__[type] !== 'function') {
184
+ routeMatch.__[type] = routeElement
185
+ }
186
+ })
186
187
  } catch (err: any) {
187
188
  console.error(err)
188
189
  const error = new (Error as any)('Invalid search params found', {
@@ -206,11 +207,42 @@ export function createRouteMatch<
206
207
  hasLoaders: () => {
207
208
  return !!(
208
209
  route.options.loader ||
209
- route.options.import ||
210
210
  elementTypes.some((d) => typeof route.options[d] === 'function')
211
211
  )
212
212
  },
213
- load: async (opts) => {
213
+ load: async (loaderOpts) => {
214
+ const now = Date.now()
215
+ const minMaxAge = loaderOpts?.preload
216
+ ? Math.max(loaderOpts?.maxAge, loaderOpts?.gcMaxAge)
217
+ : 0
218
+
219
+ // If this is a preload, add it to the preload cache
220
+ if (loaderOpts?.preload && minMaxAge > 0) {
221
+ // If the match is currently active, don't preload it
222
+ if (
223
+ router.state.matches.find((d) => d.matchId === routeMatch.matchId)
224
+ ) {
225
+ return
226
+ }
227
+
228
+ router.matchCache[routeMatch.matchId] = {
229
+ gc: now + loaderOpts.gcMaxAge,
230
+ match: routeMatch as RouteMatch<any, any>,
231
+ }
232
+ }
233
+
234
+ // If the match is invalid, errored or idle, trigger it to load
235
+ if (
236
+ (routeMatch.status === 'success' && routeMatch.getIsInvalid()) ||
237
+ routeMatch.status === 'error' ||
238
+ routeMatch.status === 'idle'
239
+ ) {
240
+ const maxAge = loaderOpts?.preload ? loaderOpts?.maxAge : undefined
241
+
242
+ await routeMatch.fetch({ maxAge })
243
+ }
244
+ },
245
+ fetch: async (opts) => {
214
246
  const id = '' + Date.now() + Math.random()
215
247
  routeMatch.__.latestId = id
216
248
 
@@ -230,27 +262,8 @@ export function createRouteMatch<
230
262
  routeMatch.isFetching = true
231
263
  routeMatch.__.resolve = resolve as () => void
232
264
 
233
- const loaderPromise = (async () => {
234
- const importer = routeMatch.options.import
235
-
236
- // First, run any importers
237
- if (importer) {
238
- routeMatch.__.importPromise = importer({
239
- params: routeMatch.params,
240
- // search: routeMatch.search,
241
- }).then((imported) => {
242
- routeMatch.__ = {
243
- ...routeMatch.__,
244
- ...imported,
245
- }
246
- })
247
- }
248
-
249
- // Wait for the importer to finish before
250
- // attempting to load elements and data
251
- await routeMatch.__.importPromise
252
-
253
- // Next, load the elements and data in parallel
265
+ routeMatch.__.loaderDataPromise = (async () => {
266
+ // Load the elements and data in parallel
254
267
 
255
268
  routeMatch.__.elementsPromise = (async () => {
256
269
  // then run all element and data loaders in parallel
@@ -260,16 +273,10 @@ export function createRouteMatch<
260
273
  elementTypes.map(async (type) => {
261
274
  const routeElement = routeMatch.options[type]
262
275
 
263
- if (routeMatch.__[type]) {
264
- return
265
- }
266
-
267
- if (typeof routeElement === 'function') {
268
- const res = await (routeElement as any)(routeMatch)
269
-
270
- routeMatch.__[type] = res
271
- } else {
272
- routeMatch.__[type] = routeMatch.options[type] as any
276
+ if (typeof routeMatch.__[type] === 'function') {
277
+ routeMatch.__[type] = await router.options.createElement!(
278
+ routeElement,
279
+ )
273
280
  }
274
281
  }),
275
282
  )
@@ -284,7 +291,7 @@ export function createRouteMatch<
284
291
  signal: routeMatch.__.abortController.signal,
285
292
  })
286
293
  if (id !== routeMatch.__.latestId) {
287
- return routeMatch.__.loaderPromise
294
+ return routeMatch.__.loadPromise
288
295
  }
289
296
 
290
297
  routeMatch.routeLoaderData = replaceEqualDeep(
@@ -304,7 +311,7 @@ export function createRouteMatch<
304
311
  0)
305
312
  } catch (err) {
306
313
  if (id !== routeMatch.__.latestId) {
307
- return routeMatch.__.loaderPromise
314
+ return routeMatch.__.loadPromise
308
315
  }
309
316
 
310
317
  if (process.env.NODE_ENV !== 'production') {
@@ -322,7 +329,7 @@ export function createRouteMatch<
322
329
  routeMatch.__.dataPromise,
323
330
  ])
324
331
  if (id !== routeMatch.__.latestId) {
325
- return routeMatch.__.loaderPromise
332
+ return routeMatch.__.loadPromise
326
333
  }
327
334
 
328
335
  if (routeMatch.__.pendingMinPromise) {
@@ -331,7 +338,7 @@ export function createRouteMatch<
331
338
  }
332
339
  } finally {
333
340
  if (id !== routeMatch.__.latestId) {
334
- return routeMatch.__.loaderPromise
341
+ return routeMatch.__.loadPromise
335
342
  }
336
343
  routeMatch.__.cancelPending()
337
344
  routeMatch.isPending = false
@@ -340,16 +347,18 @@ export function createRouteMatch<
340
347
  }
341
348
  })()
342
349
 
343
- routeMatch.__.loaderPromise = loaderPromise
344
- await loaderPromise
350
+ await routeMatch.__.loaderDataPromise
345
351
 
346
352
  if (id !== routeMatch.__.latestId) {
347
- return routeMatch.__.loaderPromise
353
+ return routeMatch.__.loadPromise
348
354
  }
349
- delete routeMatch.__.loaderPromise
355
+
356
+ delete routeMatch.__.loaderDataPromise
350
357
  })
351
358
 
352
- return await routeMatch.__.loadPromise
359
+ await routeMatch.__.loadPromise
360
+
361
+ delete routeMatch.__.loadPromise
353
362
  },
354
363
  }
355
364