Skip to content

Commit 6f2831b

Browse files
committed
fix: expose parentLoaderPromise to immediate child loader
1 parent 3b07142 commit 6f2831b

File tree

6 files changed

+66
-22
lines changed

6 files changed

+66
-22
lines changed

examples/react/basic-ssr-lite/src/routeConfig.tsx

+12-10
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,23 @@ export const routeConfig = createRouteConfig().createChildren((createRoute) => [
1818
path: 'posts',
1919
component: Posts,
2020
errorComponent: () => 'Oh crap!',
21-
loader: async () => {
22-
return {
23-
posts: await fetchPosts(),
24-
}
25-
},
21+
// loader: async () => {
22+
// return {
23+
// posts: await fetchPosts(),
24+
// }
25+
// },
26+
// loader: {...}
2627
}).createChildren((createRoute) => [
2728
createRoute({ path: '/', component: PostsIndex }),
2829
createRoute({
2930
path: ':postId',
3031
component: Post,
31-
loader: async ({ params: { postId } }) => {
32-
return {
33-
post: await fetchPostById(postId),
34-
}
35-
},
32+
// loader: async ({ params: { postId } }) => {
33+
// return {
34+
// post: await fetchPostById(postId),
35+
// }
36+
// },
37+
// loader: {...}
3638
}),
3739
]),
3840
])

examples/react/basic-ssr-lite/vite.config.ts

+2
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,5 @@ function myBabelPlugin(): babel.PluginObj {
5858
},
5959
}
6060
}
61+
62+
function test() {}

packages/router-core/src/routeConfig.ts

+35-10
Original file line numberDiff line numberDiff line change
@@ -50,20 +50,27 @@ export type ParentParams<TParentParams> = AnyPathParams extends TParentParams
5050
}
5151

5252
export type LoaderFn<
53-
TRouteLoaderData extends AnyLoaderData,
53+
TParentRouteLoaderData extends AnyLoaderData = {},
54+
TRouteLoaderData extends AnyLoaderData = {},
5455
TFullSearchSchema extends AnySearchSchema = {},
5556
TAllParams extends AnyPathParams = {},
5657
> = (
57-
loaderContext: LoaderContext<TFullSearchSchema, TAllParams>,
58+
loaderContext: LoaderContext<
59+
TParentRouteLoaderData,
60+
TFullSearchSchema,
61+
TAllParams
62+
>,
5863
) => Promise<TRouteLoaderData>
5964

6065
export interface LoaderContext<
66+
TParentRouteLoaderData extends AnyLoaderData = {},
6167
TFullSearchSchema extends AnySearchSchema = {},
6268
TAllParams extends AnyPathParams = {},
6369
> {
6470
params: TAllParams
6571
search: TFullSearchSchema
6672
signal?: AbortSignal
73+
parentLoaderPromise?: Promise<TParentRouteLoaderData>
6774
}
6875

6976
export type ActionFn<TActionPayload = unknown, TActionResponse = unknown> = (
@@ -77,6 +84,7 @@ export type UnloaderFn<TPath extends string> = (
7784
export type RouteOptions<
7885
TRouteId extends string = string,
7986
TPath extends string = string,
87+
TParentRouteLoaderData extends AnyLoaderData = {},
8088
TRouteLoaderData extends AnyLoaderData = {},
8189
TLoaderData extends AnyLoaderData = {},
8290
TActionPayload = unknown,
@@ -109,13 +117,18 @@ export type RouteOptions<
109117
// calls that match this route.
110118
postSearchFilters?: SearchFilter<TFullSearchSchema>[]
111119
// The content to be rendered when the route is matched. If no component is provided, defaults to `<Outlet />`
112-
component?: GetFrameworkGeneric<'Component'> // , NoInfer<TLoaderData>>
120+
component?: GetFrameworkGeneric<'Component'> // , NoInfer<TParentLoaderData>>
113121
// The content to be rendered when the route encounters an error
114-
errorComponent?: GetFrameworkGeneric<'Component'> // , NoInfer<TLoaderData>>
122+
errorComponent?: GetFrameworkGeneric<'Component'> // , NoInfer<TParentLoaderData>>
115123
// If supported by your framework, the content to be rendered as the fallback content until the route is ready to render
116-
pendingComponent?: GetFrameworkGeneric<'Component'> //, NoInfer<TLoaderData>>
124+
pendingComponent?: GetFrameworkGeneric<'Component'> //, NoInfer<TParentLoaderData>>
117125
// An asynchronous function responsible for preparing or fetching data for the route before it is rendered
118-
loader?: LoaderFn<TRouteLoaderData, TFullSearchSchema, TAllParams>
126+
loader?: LoaderFn<
127+
TParentRouteLoaderData,
128+
TRouteLoaderData,
129+
TFullSearchSchema,
130+
TAllParams
131+
>
119132
// The max age to consider loader data fresh (not-stale) for this route in milliseconds from the time of fetch
120133
// Defaults to 0. Only stale loader data is refetched.
121134
loaderMaxAge?: number
@@ -171,6 +184,7 @@ export interface RouteConfig<
171184
TRouteId extends string = string,
172185
TPath extends string = string,
173186
TFullPath extends string = string,
187+
TParentRouteLoaderData extends AnyLoaderData = AnyLoaderData,
174188
TRouteLoaderData extends AnyLoaderData = AnyLoaderData,
175189
TLoaderData extends AnyLoaderData = AnyLoaderData,
176190
TActionPayload = unknown,
@@ -193,6 +207,7 @@ export interface RouteConfig<
193207
options: RouteOptions<
194208
TRouteId,
195209
TPath,
210+
TParentRouteLoaderData,
196211
TRouteLoaderData,
197212
TLoaderData,
198213
TActionPayload,
@@ -217,6 +232,7 @@ export interface RouteConfig<
217232
TRouteId,
218233
TPath,
219234
TFullPath,
235+
TParentRouteLoaderData,
220236
TRouteLoaderData,
221237
TLoaderData,
222238
TActionPayload,
@@ -239,6 +255,7 @@ export interface RouteConfig<
239255
false,
240256
TId,
241257
TFullPath,
258+
TRouteLoaderData,
242259
TLoaderData,
243260
TFullSearchSchema,
244261
TAllParams
@@ -251,6 +268,7 @@ export interface RouteConfig<
251268
TRouteId,
252269
TPath,
253270
TFullPath,
271+
TParentRouteLoaderData,
254272
TRouteLoaderData,
255273
TLoaderData,
256274
TActionPayload,
@@ -268,6 +286,7 @@ export interface RouteConfig<
268286
false,
269287
TId,
270288
TFullPath,
289+
TRouteLoaderData,
271290
TLoaderData,
272291
TFullSearchSchema,
273292
TAllParams
@@ -278,7 +297,8 @@ type CreateRouteConfigFn<
278297
TIsRoot extends boolean = false,
279298
TParentId extends string = string,
280299
TParentPath extends string = string,
281-
TParentAllLoaderData extends AnyLoaderData = {},
300+
TParentRouteLoaderData extends AnyLoaderData = {},
301+
TParentLoaderData extends AnyLoaderData = {},
282302
TParentSearchSchema extends AnySearchSchema = {},
283303
TParentParams extends AnyPathParams = {},
284304
> = <
@@ -309,8 +329,9 @@ type CreateRouteConfigFn<
309329
RouteOptions<
310330
TRouteId,
311331
TPath,
332+
TParentRouteLoaderData,
312333
TRouteLoaderData,
313-
Expand<TParentAllLoaderData & DeepAwaited<NoInfer<TRouteLoaderData>>>,
334+
Expand<TParentLoaderData & DeepAwaited<NoInfer<TRouteLoaderData>>>,
314335
TActionPayload,
315336
TActionResponse,
316337
TParentSearchSchema,
@@ -325,8 +346,9 @@ type CreateRouteConfigFn<
325346
: RouteOptions<
326347
TRouteId,
327348
TPath,
349+
TParentRouteLoaderData,
328350
TRouteLoaderData,
329-
Expand<TParentAllLoaderData & DeepAwaited<NoInfer<TRouteLoaderData>>>,
351+
Expand<TParentLoaderData & DeepAwaited<NoInfer<TRouteLoaderData>>>,
330352
TActionPayload,
331353
TActionResponse,
332354
TParentSearchSchema,
@@ -345,8 +367,9 @@ type CreateRouteConfigFn<
345367
TResolvedId,
346368
TPath,
347369
string extends TPath ? '' : RoutePath<RoutePrefix<TParentPath, TPath>>,
370+
TParentRouteLoaderData,
348371
TRouteLoaderData,
349-
Expand<TParentAllLoaderData & DeepAwaited<NoInfer<TRouteLoaderData>>>,
372+
Expand<TParentLoaderData & DeepAwaited<NoInfer<TRouteLoaderData>>>,
350373
TActionPayload,
351374
TActionResponse,
352375
TParentSearchSchema,
@@ -389,6 +412,7 @@ export interface AnyRouteConfig
389412
any,
390413
any,
391414
any,
415+
any,
392416
any
393417
> {}
394418

@@ -408,6 +432,7 @@ export interface AnyRouteConfigWithChildren<TChildren>
408432
any,
409433
any,
410434
any,
435+
any,
411436
TChildren
412437
> {}
413438

packages/router-core/src/routeInfo.ts

+7
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ export type RouteConfigRoute<TRouteConfig> = TRouteConfig extends RouteConfig<
6363
infer TRouteId,
6464
infer TPath,
6565
infer TFullPath,
66+
infer TParentLoaderData,
6667
infer TRouteLoaderData,
6768
infer TLoaderData,
6869
infer TActionPayload,
@@ -82,6 +83,7 @@ export type RouteConfigRoute<TRouteConfig> = TRouteConfig extends RouteConfig<
8283
TRouteId,
8384
TPath,
8485
TFullPath,
86+
TParentLoaderData,
8587
TRouteLoaderData,
8688
TLoaderData,
8789
TActionPayload,
@@ -111,6 +113,7 @@ export interface RoutesInfoInner<
111113
any,
112114
any,
113115
any,
116+
any,
114117
any
115118
> = RouteInfo,
116119
TRouteInfoById = {
@@ -147,6 +150,7 @@ export interface AnyRouteInfo
147150
any,
148151
any,
149152
any,
153+
any,
150154
any
151155
> {}
152156

@@ -155,6 +159,7 @@ export interface RouteInfo<
155159
TRouteId extends string = string,
156160
TPath extends string = string,
157161
TFullPath extends string = string,
162+
TParentRouteLoaderData extends AnyLoaderData = {},
158163
TRouteLoaderData extends AnyLoaderData = {},
159164
TLoaderData extends AnyLoaderData = {},
160165
TActionPayload = unknown,
@@ -173,6 +178,7 @@ export interface RouteInfo<
173178
routeId: TRouteId
174179
path: TPath
175180
fullPath: TFullPath
181+
parentRouteLoaderData: TParentRouteLoaderData
176182
routeLoaderData: TRouteLoaderData
177183
loaderData: TLoaderData
178184
actionPayload: TActionPayload
@@ -185,6 +191,7 @@ export interface RouteInfo<
185191
options: RouteOptions<
186192
TRouteId,
187193
TPath,
194+
TParentRouteLoaderData,
188195
TRouteLoaderData,
189196
TLoaderData,
190197
TActionPayload,

packages/router-core/src/routeMatch.ts

+9-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export interface RouteMatch<
3535
pendingComponent?: GetFrameworkGeneric<'Component'> // , TRouteInfo['loaderData']>
3636
loadPromise?: Promise<void>
3737
componentsPromise?: Promise<void>
38-
dataPromise?: Promise<void>
38+
dataPromise?: Promise<TRouteInfo['routeLoaderData']>
3939
onExit?:
4040
| void
4141
| ((matchContext: {
@@ -74,6 +74,7 @@ export function createRouteMatch<
7474
router: Router<any, any>,
7575
route: Route<TAllRouteInfo, TRouteInfo>,
7676
opts: {
77+
parentMatch?: RouteMatch<any, any>
7778
matchId: string
7879
params: TRouteInfo['allParams']
7980
pathname: string
@@ -240,6 +241,7 @@ export function createRouteMatch<
240241
try {
241242
if (routeMatch.options.loader) {
242243
const data = await routeMatch.options.loader({
244+
parentLoaderPromise: routeMatch.parentMatch?.__.dataPromise,
243245
params: routeMatch.params,
244246
search: routeMatch.routeSearch,
245247
signal: routeMatch.__.abortController.signal,
@@ -263,6 +265,8 @@ export function createRouteMatch<
263265
routeMatch.options.loaderMaxAge ??
264266
router.options.defaultLoaderMaxAge ??
265267
0)
268+
269+
return routeMatch.routeLoaderData
266270
} catch (err) {
267271
if (id !== routeMatch.__.latestId) {
268272
return routeMatch.__.loadPromise
@@ -271,16 +275,19 @@ export function createRouteMatch<
271275
if (process.env.NODE_ENV !== 'production') {
272276
console.error(err)
273277
}
278+
274279
routeMatch.error = err
275280
routeMatch.status = 'error'
276281
routeMatch.updatedAt = Date.now()
282+
283+
throw err
277284
}
278285
})
279286

280287
try {
281288
await Promise.all([
282289
routeMatch.__.componentsPromise,
283-
routeMatch.__.dataPromise,
290+
routeMatch.__.dataPromise.catch(() => {}),
284291
])
285292
if (id !== routeMatch.__.latestId) {
286293
return routeMatch.__.loadPromise

packages/router-core/src/router.ts

+1
Original file line numberDiff line numberDiff line change
@@ -811,6 +811,7 @@ export function createRouter<
811811
existingMatches.find((d) => d.matchId === matchId) ||
812812
router.matchCache[matchId]?.match ||
813813
createRouteMatch(router, foundRoute, {
814+
parentMatch,
814815
matchId,
815816
params,
816817
pathname: joinPaths([pathname, interpolatedPath]),

0 commit comments

Comments
 (0)