@remix-run/router 1.19.2 → 1.20.0-pre.0
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/CHANGELOG.md +27 -0
- package/dist/index.d.ts +2 -2
- package/dist/router.cjs.js +188 -174
- package/dist/router.cjs.js.map +1 -1
- package/dist/router.d.ts +8 -8
- package/dist/router.js +180 -171
- package/dist/router.js.map +1 -1
- package/dist/router.umd.js +188 -174
- package/dist/router.umd.js.map +1 -1
- package/dist/router.umd.min.js +2 -2
- package/dist/router.umd.min.js.map +1 -1
- package/dist/utils.d.ts +6 -7
- package/index.ts +7 -6
- package/package.json +1 -1
- package/router.ts +235 -216
- package/utils.ts +14 -8
package/router.ts
CHANGED
|
@@ -391,8 +391,8 @@ export interface RouterInit {
|
|
|
391
391
|
future?: Partial<FutureConfig>;
|
|
392
392
|
hydrationData?: HydrationState;
|
|
393
393
|
window?: Window;
|
|
394
|
-
|
|
395
|
-
|
|
394
|
+
dataStrategy?: DataStrategyFunction;
|
|
395
|
+
patchRoutesOnNavigation?: AgnosticPatchRoutesOnNavigationFunction;
|
|
396
396
|
}
|
|
397
397
|
|
|
398
398
|
/**
|
|
@@ -422,7 +422,7 @@ export interface StaticHandler {
|
|
|
422
422
|
opts?: {
|
|
423
423
|
requestContext?: unknown;
|
|
424
424
|
skipLoaderErrorBubbling?: boolean;
|
|
425
|
-
|
|
425
|
+
dataStrategy?: DataStrategyFunction;
|
|
426
426
|
}
|
|
427
427
|
): Promise<StaticHandlerContext | Response>;
|
|
428
428
|
queryRoute(
|
|
@@ -430,7 +430,7 @@ export interface StaticHandler {
|
|
|
430
430
|
opts?: {
|
|
431
431
|
routeId?: string;
|
|
432
432
|
requestContext?: unknown;
|
|
433
|
-
|
|
433
|
+
dataStrategy?: DataStrategyFunction;
|
|
434
434
|
}
|
|
435
435
|
): Promise<any>;
|
|
436
436
|
}
|
|
@@ -448,8 +448,8 @@ export interface RouterSubscriber {
|
|
|
448
448
|
state: RouterState,
|
|
449
449
|
opts: {
|
|
450
450
|
deletedFetchers: string[];
|
|
451
|
-
|
|
452
|
-
|
|
451
|
+
viewTransitionOpts?: ViewTransitionOpts;
|
|
452
|
+
flushSync: boolean;
|
|
453
453
|
}
|
|
454
454
|
): void;
|
|
455
455
|
}
|
|
@@ -475,7 +475,7 @@ export type RelativeRoutingType = "route" | "path";
|
|
|
475
475
|
type BaseNavigateOrFetchOptions = {
|
|
476
476
|
preventScrollReset?: boolean;
|
|
477
477
|
relative?: RelativeRoutingType;
|
|
478
|
-
|
|
478
|
+
flushSync?: boolean;
|
|
479
479
|
};
|
|
480
480
|
|
|
481
481
|
// Only allowed for navigations
|
|
@@ -483,7 +483,7 @@ type BaseNavigateOptions = BaseNavigateOrFetchOptions & {
|
|
|
483
483
|
replace?: boolean;
|
|
484
484
|
state?: any;
|
|
485
485
|
fromRouteId?: string;
|
|
486
|
-
|
|
486
|
+
viewTransition?: boolean;
|
|
487
487
|
};
|
|
488
488
|
|
|
489
489
|
// Only allowed for submission navigations
|
|
@@ -797,8 +797,8 @@ export function createRouter(init: RouterInit): Router {
|
|
|
797
797
|
);
|
|
798
798
|
let inFlightDataRoutes: AgnosticDataRouteObject[] | undefined;
|
|
799
799
|
let basename = init.basename || "/";
|
|
800
|
-
let dataStrategyImpl = init.
|
|
801
|
-
let patchRoutesOnNavigationImpl = init.
|
|
800
|
+
let dataStrategyImpl = init.dataStrategy || defaultDataStrategy;
|
|
801
|
+
let patchRoutesOnNavigationImpl = init.patchRoutesOnNavigation;
|
|
802
802
|
|
|
803
803
|
// Config driven behavior flags
|
|
804
804
|
let future: FutureConfig = {
|
|
@@ -814,10 +814,6 @@ export function createRouter(init: RouterInit): Router {
|
|
|
814
814
|
let unlistenHistory: (() => void) | null = null;
|
|
815
815
|
// Externally-provided functions to call on all state changes
|
|
816
816
|
let subscribers = new Set<RouterSubscriber>();
|
|
817
|
-
// FIFO queue of previously discovered routes to prevent re-calling on
|
|
818
|
-
// subsequent navigations to the same path
|
|
819
|
-
let discoveredRoutesMaxSize = 1000;
|
|
820
|
-
let discoveredRoutes = new Set<string>();
|
|
821
817
|
// Externally-provided object to hold scroll restoration locations during routing
|
|
822
818
|
let savedScrollPositions: Record<string, number> | null = null;
|
|
823
819
|
// Externally-provided function to get scroll restoration keys
|
|
@@ -894,33 +890,18 @@ export function createRouter(init: RouterInit): Router {
|
|
|
894
890
|
// were marked for explicit hydration
|
|
895
891
|
let loaderData = init.hydrationData ? init.hydrationData.loaderData : null;
|
|
896
892
|
let errors = init.hydrationData ? init.hydrationData.errors : null;
|
|
897
|
-
let isRouteInitialized = (m: AgnosticDataRouteMatch) => {
|
|
898
|
-
// No loader, nothing to initialize
|
|
899
|
-
if (!m.route.loader) {
|
|
900
|
-
return true;
|
|
901
|
-
}
|
|
902
|
-
// Explicitly opting-in to running on hydration
|
|
903
|
-
if (
|
|
904
|
-
typeof m.route.loader === "function" &&
|
|
905
|
-
m.route.loader.hydrate === true
|
|
906
|
-
) {
|
|
907
|
-
return false;
|
|
908
|
-
}
|
|
909
|
-
// Otherwise, initialized if hydrated with data or an error
|
|
910
|
-
return (
|
|
911
|
-
(loaderData && loaderData[m.route.id] !== undefined) ||
|
|
912
|
-
(errors && errors[m.route.id] !== undefined)
|
|
913
|
-
);
|
|
914
|
-
};
|
|
915
|
-
|
|
916
893
|
// If errors exist, don't consider routes below the boundary
|
|
917
894
|
if (errors) {
|
|
918
895
|
let idx = initialMatches.findIndex(
|
|
919
896
|
(m) => errors![m.route.id] !== undefined
|
|
920
897
|
);
|
|
921
|
-
initialized = initialMatches
|
|
898
|
+
initialized = initialMatches
|
|
899
|
+
.slice(0, idx + 1)
|
|
900
|
+
.every((m) => !shouldLoadRouteOnHydration(m.route, loaderData, errors));
|
|
922
901
|
} else {
|
|
923
|
-
initialized = initialMatches.every(
|
|
902
|
+
initialized = initialMatches.every(
|
|
903
|
+
(m) => !shouldLoadRouteOnHydration(m.route, loaderData, errors)
|
|
904
|
+
);
|
|
924
905
|
}
|
|
925
906
|
} else {
|
|
926
907
|
// Without partial hydration - we're initialized if we were provided any
|
|
@@ -1187,8 +1168,8 @@ export function createRouter(init: RouterInit): Router {
|
|
|
1187
1168
|
[...subscribers].forEach((subscriber) =>
|
|
1188
1169
|
subscriber(state, {
|
|
1189
1170
|
deletedFetchers: deletedFetchersKeys,
|
|
1190
|
-
|
|
1191
|
-
|
|
1171
|
+
viewTransitionOpts: opts.viewTransitionOpts,
|
|
1172
|
+
flushSync: opts.flushSync === true,
|
|
1192
1173
|
})
|
|
1193
1174
|
);
|
|
1194
1175
|
|
|
@@ -1411,7 +1392,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
1411
1392
|
? opts.preventScrollReset === true
|
|
1412
1393
|
: undefined;
|
|
1413
1394
|
|
|
1414
|
-
let flushSync = (opts && opts.
|
|
1395
|
+
let flushSync = (opts && opts.flushSync) === true;
|
|
1415
1396
|
|
|
1416
1397
|
let blockerKey = shouldBlockNavigation({
|
|
1417
1398
|
currentLocation,
|
|
@@ -1450,7 +1431,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
1450
1431
|
pendingError: error,
|
|
1451
1432
|
preventScrollReset,
|
|
1452
1433
|
replace: opts && opts.replace,
|
|
1453
|
-
enableViewTransition: opts && opts.
|
|
1434
|
+
enableViewTransition: opts && opts.viewTransition,
|
|
1454
1435
|
flushSync,
|
|
1455
1436
|
});
|
|
1456
1437
|
}
|
|
@@ -1559,7 +1540,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
1559
1540
|
// Short circuit if it's only a hash change and not a revalidation or
|
|
1560
1541
|
// mutation submission.
|
|
1561
1542
|
//
|
|
1562
|
-
// Ignore on initial page loads because since the initial
|
|
1543
|
+
// Ignore on initial page loads because since the initial hydration will always
|
|
1563
1544
|
// be "same hash". For example, on /page#hash and submit a <Form method="post">
|
|
1564
1545
|
// which will default to a navigation to /page
|
|
1565
1546
|
if (
|
|
@@ -1983,9 +1964,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
1983
1964
|
}
|
|
1984
1965
|
|
|
1985
1966
|
revalidatingFetchers.forEach((rf) => {
|
|
1986
|
-
|
|
1987
|
-
abortFetcher(rf.key);
|
|
1988
|
-
}
|
|
1967
|
+
abortFetcher(rf.key);
|
|
1989
1968
|
if (rf.controller) {
|
|
1990
1969
|
// Fetchers use an independent AbortController so that aborting a fetcher
|
|
1991
1970
|
// (via deleteFetcher) does not abort the triggering navigation that
|
|
@@ -2026,6 +2005,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
2026
2005
|
abortPendingFetchRevalidations
|
|
2027
2006
|
);
|
|
2028
2007
|
}
|
|
2008
|
+
|
|
2029
2009
|
revalidatingFetchers.forEach((rf) => fetchControllers.delete(rf.key));
|
|
2030
2010
|
|
|
2031
2011
|
// If any loaders returned a redirect Response, start a new REPLACE navigation
|
|
@@ -2053,7 +2033,6 @@ export function createRouter(init: RouterInit): Router {
|
|
|
2053
2033
|
let { loaderData, errors } = processLoaderData(
|
|
2054
2034
|
state,
|
|
2055
2035
|
matches,
|
|
2056
|
-
matchesToLoad,
|
|
2057
2036
|
loaderResults,
|
|
2058
2037
|
pendingActionResult,
|
|
2059
2038
|
revalidatingFetchers,
|
|
@@ -2073,13 +2052,9 @@ export function createRouter(init: RouterInit): Router {
|
|
|
2073
2052
|
});
|
|
2074
2053
|
});
|
|
2075
2054
|
|
|
2076
|
-
//
|
|
2055
|
+
// Preserve SSR errors during partial hydration
|
|
2077
2056
|
if (future.v7_partialHydration && initialHydration && state.errors) {
|
|
2078
|
-
|
|
2079
|
-
.filter(([id]) => !matchesToLoad.some((m) => m.route.id === id))
|
|
2080
|
-
.forEach(([routeId, error]) => {
|
|
2081
|
-
errors = Object.assign(errors || {}, { [routeId]: error });
|
|
2082
|
-
});
|
|
2057
|
+
errors = { ...state.errors, ...errors };
|
|
2083
2058
|
}
|
|
2084
2059
|
|
|
2085
2060
|
let updatedFetchers = markFetchRedirectsDone();
|
|
@@ -2143,8 +2118,9 @@ export function createRouter(init: RouterInit): Router {
|
|
|
2143
2118
|
);
|
|
2144
2119
|
}
|
|
2145
2120
|
|
|
2146
|
-
|
|
2147
|
-
|
|
2121
|
+
abortFetcher(key);
|
|
2122
|
+
|
|
2123
|
+
let flushSync = (opts && opts.flushSync) === true;
|
|
2148
2124
|
|
|
2149
2125
|
let routesToUse = inFlightDataRoutes || dataRoutes;
|
|
2150
2126
|
let normalizedPath = normalizeTo(
|
|
@@ -2188,7 +2164,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
2188
2164
|
|
|
2189
2165
|
let match = getTargetMatch(matches, path);
|
|
2190
2166
|
|
|
2191
|
-
|
|
2167
|
+
let preventScrollReset = (opts && opts.preventScrollReset) === true;
|
|
2192
2168
|
|
|
2193
2169
|
if (submission && isMutationMethod(submission.formMethod)) {
|
|
2194
2170
|
handleFetcherAction(
|
|
@@ -2199,6 +2175,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
2199
2175
|
matches,
|
|
2200
2176
|
fogOfWar.active,
|
|
2201
2177
|
flushSync,
|
|
2178
|
+
preventScrollReset,
|
|
2202
2179
|
submission
|
|
2203
2180
|
);
|
|
2204
2181
|
return;
|
|
@@ -2215,6 +2192,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
2215
2192
|
matches,
|
|
2216
2193
|
fogOfWar.active,
|
|
2217
2194
|
flushSync,
|
|
2195
|
+
preventScrollReset,
|
|
2218
2196
|
submission
|
|
2219
2197
|
);
|
|
2220
2198
|
}
|
|
@@ -2229,6 +2207,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
2229
2207
|
requestMatches: AgnosticDataRouteMatch[],
|
|
2230
2208
|
isFogOfWar: boolean,
|
|
2231
2209
|
flushSync: boolean,
|
|
2210
|
+
preventScrollReset: boolean,
|
|
2232
2211
|
submission: Submission
|
|
2233
2212
|
) {
|
|
2234
2213
|
interruptActiveLoads();
|
|
@@ -2343,6 +2322,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
2343
2322
|
updateFetcherState(key, getLoadingFetcher(submission));
|
|
2344
2323
|
return startRedirectNavigation(fetchRequest, actionResult, false, {
|
|
2345
2324
|
fetcherSubmission: submission,
|
|
2325
|
+
preventScrollReset,
|
|
2346
2326
|
});
|
|
2347
2327
|
}
|
|
2348
2328
|
}
|
|
@@ -2412,9 +2392,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
2412
2392
|
existingFetcher ? existingFetcher.data : undefined
|
|
2413
2393
|
);
|
|
2414
2394
|
state.fetchers.set(staleKey, revalidatingFetcher);
|
|
2415
|
-
|
|
2416
|
-
abortFetcher(staleKey);
|
|
2417
|
-
}
|
|
2395
|
+
abortFetcher(staleKey);
|
|
2418
2396
|
if (rf.controller) {
|
|
2419
2397
|
fetchControllers.set(staleKey, rf.controller);
|
|
2420
2398
|
}
|
|
@@ -2457,7 +2435,8 @@ export function createRouter(init: RouterInit): Router {
|
|
|
2457
2435
|
return startRedirectNavigation(
|
|
2458
2436
|
revalidationRequest,
|
|
2459
2437
|
redirect.result,
|
|
2460
|
-
false
|
|
2438
|
+
false,
|
|
2439
|
+
{ preventScrollReset }
|
|
2461
2440
|
);
|
|
2462
2441
|
}
|
|
2463
2442
|
|
|
@@ -2470,7 +2449,8 @@ export function createRouter(init: RouterInit): Router {
|
|
|
2470
2449
|
return startRedirectNavigation(
|
|
2471
2450
|
revalidationRequest,
|
|
2472
2451
|
redirect.result,
|
|
2473
|
-
false
|
|
2452
|
+
false,
|
|
2453
|
+
{ preventScrollReset }
|
|
2474
2454
|
);
|
|
2475
2455
|
}
|
|
2476
2456
|
|
|
@@ -2478,7 +2458,6 @@ export function createRouter(init: RouterInit): Router {
|
|
|
2478
2458
|
let { loaderData, errors } = processLoaderData(
|
|
2479
2459
|
state,
|
|
2480
2460
|
matches,
|
|
2481
|
-
matchesToLoad,
|
|
2482
2461
|
loaderResults,
|
|
2483
2462
|
undefined,
|
|
2484
2463
|
revalidatingFetchers,
|
|
@@ -2538,6 +2517,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
2538
2517
|
matches: AgnosticDataRouteMatch[],
|
|
2539
2518
|
isFogOfWar: boolean,
|
|
2540
2519
|
flushSync: boolean,
|
|
2520
|
+
preventScrollReset: boolean,
|
|
2541
2521
|
submission?: Submission
|
|
2542
2522
|
) {
|
|
2543
2523
|
let existingFetcher = state.fetchers.get(key);
|
|
@@ -2634,7 +2614,9 @@ export function createRouter(init: RouterInit): Router {
|
|
|
2634
2614
|
return;
|
|
2635
2615
|
} else {
|
|
2636
2616
|
fetchRedirectIds.add(key);
|
|
2637
|
-
await startRedirectNavigation(fetchRequest, result, false
|
|
2617
|
+
await startRedirectNavigation(fetchRequest, result, false, {
|
|
2618
|
+
preventScrollReset,
|
|
2619
|
+
});
|
|
2638
2620
|
return;
|
|
2639
2621
|
}
|
|
2640
2622
|
}
|
|
@@ -2677,10 +2659,12 @@ export function createRouter(init: RouterInit): Router {
|
|
|
2677
2659
|
{
|
|
2678
2660
|
submission,
|
|
2679
2661
|
fetcherSubmission,
|
|
2662
|
+
preventScrollReset,
|
|
2680
2663
|
replace,
|
|
2681
2664
|
}: {
|
|
2682
2665
|
submission?: Submission;
|
|
2683
2666
|
fetcherSubmission?: Submission;
|
|
2667
|
+
preventScrollReset?: boolean;
|
|
2684
2668
|
replace?: boolean;
|
|
2685
2669
|
} = {}
|
|
2686
2670
|
) {
|
|
@@ -2761,7 +2745,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
2761
2745
|
formAction: location,
|
|
2762
2746
|
},
|
|
2763
2747
|
// Preserve these flags across redirects
|
|
2764
|
-
preventScrollReset: pendingPreventScrollReset,
|
|
2748
|
+
preventScrollReset: preventScrollReset || pendingPreventScrollReset,
|
|
2765
2749
|
enableViewTransition: isNavigation
|
|
2766
2750
|
? pendingViewTransitionEnabled
|
|
2767
2751
|
: undefined,
|
|
@@ -2778,7 +2762,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
2778
2762
|
// Send fetcher submissions through for shouldRevalidate
|
|
2779
2763
|
fetcherSubmission,
|
|
2780
2764
|
// Preserve these flags across redirects
|
|
2781
|
-
preventScrollReset: pendingPreventScrollReset,
|
|
2765
|
+
preventScrollReset: preventScrollReset || pendingPreventScrollReset,
|
|
2782
2766
|
enableViewTransition: isNavigation
|
|
2783
2767
|
? pendingViewTransitionEnabled
|
|
2784
2768
|
: undefined,
|
|
@@ -2927,8 +2911,8 @@ export function createRouter(init: RouterInit): Router {
|
|
|
2927
2911
|
fetchLoadMatches.forEach((_, key) => {
|
|
2928
2912
|
if (fetchControllers.has(key)) {
|
|
2929
2913
|
cancelledFetcherLoads.add(key);
|
|
2930
|
-
abortFetcher(key);
|
|
2931
2914
|
}
|
|
2915
|
+
abortFetcher(key);
|
|
2932
2916
|
});
|
|
2933
2917
|
}
|
|
2934
2918
|
|
|
@@ -3011,9 +2995,10 @@ export function createRouter(init: RouterInit): Router {
|
|
|
3011
2995
|
|
|
3012
2996
|
function abortFetcher(key: string) {
|
|
3013
2997
|
let controller = fetchControllers.get(key);
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
2998
|
+
if (controller) {
|
|
2999
|
+
controller.abort();
|
|
3000
|
+
fetchControllers.delete(key);
|
|
3001
|
+
}
|
|
3017
3002
|
}
|
|
3018
3003
|
|
|
3019
3004
|
function markFetchersDone(keys: string[]) {
|
|
@@ -3243,13 +3228,6 @@ export function createRouter(init: RouterInit): Router {
|
|
|
3243
3228
|
pathname: string
|
|
3244
3229
|
): { active: boolean; matches: AgnosticDataRouteMatch[] | null } {
|
|
3245
3230
|
if (patchRoutesOnNavigationImpl) {
|
|
3246
|
-
// Don't bother re-calling patchRouteOnMiss for a path we've already
|
|
3247
|
-
// processed. the last execution would have patched the route tree
|
|
3248
|
-
// accordingly so `matches` here are already accurate.
|
|
3249
|
-
if (discoveredRoutes.has(pathname)) {
|
|
3250
|
-
return { active: false, matches };
|
|
3251
|
-
}
|
|
3252
|
-
|
|
3253
3231
|
if (!matches) {
|
|
3254
3232
|
let fogMatches = matchRoutesImpl<AgnosticDataRouteObject>(
|
|
3255
3233
|
routesToUse,
|
|
@@ -3298,21 +3276,30 @@ export function createRouter(init: RouterInit): Router {
|
|
|
3298
3276
|
pathname: string,
|
|
3299
3277
|
signal: AbortSignal
|
|
3300
3278
|
): Promise<DiscoverRoutesResult> {
|
|
3279
|
+
if (!patchRoutesOnNavigationImpl) {
|
|
3280
|
+
return { type: "success", matches };
|
|
3281
|
+
}
|
|
3282
|
+
|
|
3301
3283
|
let partialMatches: AgnosticDataRouteMatch[] | null = matches;
|
|
3302
3284
|
while (true) {
|
|
3303
3285
|
let isNonHMR = inFlightDataRoutes == null;
|
|
3304
3286
|
let routesToUse = inFlightDataRoutes || dataRoutes;
|
|
3287
|
+
let localManifest = manifest;
|
|
3305
3288
|
try {
|
|
3306
|
-
await
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3289
|
+
await patchRoutesOnNavigationImpl({
|
|
3290
|
+
path: pathname,
|
|
3291
|
+
matches: partialMatches,
|
|
3292
|
+
patch: (routeId, children) => {
|
|
3293
|
+
if (signal.aborted) return;
|
|
3294
|
+
patchRoutesImpl(
|
|
3295
|
+
routeId,
|
|
3296
|
+
children,
|
|
3297
|
+
routesToUse,
|
|
3298
|
+
localManifest,
|
|
3299
|
+
mapRouteProperties
|
|
3300
|
+
);
|
|
3301
|
+
},
|
|
3302
|
+
});
|
|
3316
3303
|
} catch (e) {
|
|
3317
3304
|
return { type: "error", error: e, partialMatches };
|
|
3318
3305
|
} finally {
|
|
@@ -3322,7 +3309,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
3322
3309
|
// trigger a re-run of memoized `router.routes` dependencies.
|
|
3323
3310
|
// HMR will already update the identity and reflow when it lands
|
|
3324
3311
|
// `inFlightDataRoutes` in `completeNavigation`
|
|
3325
|
-
if (isNonHMR) {
|
|
3312
|
+
if (isNonHMR && !signal.aborted) {
|
|
3326
3313
|
dataRoutes = [...dataRoutes];
|
|
3327
3314
|
}
|
|
3328
3315
|
}
|
|
@@ -3333,7 +3320,6 @@ export function createRouter(init: RouterInit): Router {
|
|
|
3333
3320
|
|
|
3334
3321
|
let newMatches = matchRoutes(routesToUse, pathname, basename);
|
|
3335
3322
|
if (newMatches) {
|
|
3336
|
-
addToFifoQueue(pathname, discoveredRoutes);
|
|
3337
3323
|
return { type: "success", matches: newMatches };
|
|
3338
3324
|
}
|
|
3339
3325
|
|
|
@@ -3352,7 +3338,6 @@ export function createRouter(init: RouterInit): Router {
|
|
|
3352
3338
|
(m, i) => m.route.id === newPartialMatches![i].route.id
|
|
3353
3339
|
))
|
|
3354
3340
|
) {
|
|
3355
|
-
addToFifoQueue(pathname, discoveredRoutes);
|
|
3356
3341
|
return { type: "success", matches: null };
|
|
3357
3342
|
}
|
|
3358
3343
|
|
|
@@ -3360,14 +3345,6 @@ export function createRouter(init: RouterInit): Router {
|
|
|
3360
3345
|
}
|
|
3361
3346
|
}
|
|
3362
3347
|
|
|
3363
|
-
function addToFifoQueue(path: string, queue: Set<string>) {
|
|
3364
|
-
if (queue.size >= discoveredRoutesMaxSize) {
|
|
3365
|
-
let first = queue.values().next().value;
|
|
3366
|
-
queue.delete(first);
|
|
3367
|
-
}
|
|
3368
|
-
queue.add(path);
|
|
3369
|
-
}
|
|
3370
|
-
|
|
3371
3348
|
function _internalSetRoutes(newRoutes: AgnosticDataRouteObject[]) {
|
|
3372
3349
|
manifest = {};
|
|
3373
3350
|
inFlightDataRoutes = convertRoutesToDataRoutes(
|
|
@@ -3538,11 +3515,11 @@ export function createStaticHandler(
|
|
|
3538
3515
|
{
|
|
3539
3516
|
requestContext,
|
|
3540
3517
|
skipLoaderErrorBubbling,
|
|
3541
|
-
|
|
3518
|
+
dataStrategy,
|
|
3542
3519
|
}: {
|
|
3543
3520
|
requestContext?: unknown;
|
|
3544
3521
|
skipLoaderErrorBubbling?: boolean;
|
|
3545
|
-
|
|
3522
|
+
dataStrategy?: DataStrategyFunction;
|
|
3546
3523
|
} = {}
|
|
3547
3524
|
): Promise<StaticHandlerContext | Response> {
|
|
3548
3525
|
let url = new URL(request.url);
|
|
@@ -3594,7 +3571,7 @@ export function createStaticHandler(
|
|
|
3594
3571
|
location,
|
|
3595
3572
|
matches,
|
|
3596
3573
|
requestContext,
|
|
3597
|
-
|
|
3574
|
+
dataStrategy || null,
|
|
3598
3575
|
skipLoaderErrorBubbling === true,
|
|
3599
3576
|
null
|
|
3600
3577
|
);
|
|
@@ -3639,11 +3616,11 @@ export function createStaticHandler(
|
|
|
3639
3616
|
{
|
|
3640
3617
|
routeId,
|
|
3641
3618
|
requestContext,
|
|
3642
|
-
|
|
3619
|
+
dataStrategy,
|
|
3643
3620
|
}: {
|
|
3644
3621
|
requestContext?: unknown;
|
|
3645
3622
|
routeId?: string;
|
|
3646
|
-
|
|
3623
|
+
dataStrategy?: DataStrategyFunction;
|
|
3647
3624
|
} = {}
|
|
3648
3625
|
): Promise<any> {
|
|
3649
3626
|
let url = new URL(request.url);
|
|
@@ -3677,7 +3654,7 @@ export function createStaticHandler(
|
|
|
3677
3654
|
location,
|
|
3678
3655
|
matches,
|
|
3679
3656
|
requestContext,
|
|
3680
|
-
|
|
3657
|
+
dataStrategy || null,
|
|
3681
3658
|
false,
|
|
3682
3659
|
match
|
|
3683
3660
|
);
|
|
@@ -3716,7 +3693,7 @@ export function createStaticHandler(
|
|
|
3716
3693
|
location: Location,
|
|
3717
3694
|
matches: AgnosticDataRouteMatch[],
|
|
3718
3695
|
requestContext: unknown,
|
|
3719
|
-
|
|
3696
|
+
dataStrategy: DataStrategyFunction | null,
|
|
3720
3697
|
skipLoaderErrorBubbling: boolean,
|
|
3721
3698
|
routeMatch: AgnosticDataRouteMatch | null
|
|
3722
3699
|
): Promise<Omit<StaticHandlerContext, "location" | "basename"> | Response> {
|
|
@@ -3732,7 +3709,7 @@ export function createStaticHandler(
|
|
|
3732
3709
|
matches,
|
|
3733
3710
|
routeMatch || getTargetMatch(matches, location),
|
|
3734
3711
|
requestContext,
|
|
3735
|
-
|
|
3712
|
+
dataStrategy,
|
|
3736
3713
|
skipLoaderErrorBubbling,
|
|
3737
3714
|
routeMatch != null
|
|
3738
3715
|
);
|
|
@@ -3743,7 +3720,7 @@ export function createStaticHandler(
|
|
|
3743
3720
|
request,
|
|
3744
3721
|
matches,
|
|
3745
3722
|
requestContext,
|
|
3746
|
-
|
|
3723
|
+
dataStrategy,
|
|
3747
3724
|
skipLoaderErrorBubbling,
|
|
3748
3725
|
routeMatch
|
|
3749
3726
|
);
|
|
@@ -3778,7 +3755,7 @@ export function createStaticHandler(
|
|
|
3778
3755
|
matches: AgnosticDataRouteMatch[],
|
|
3779
3756
|
actionMatch: AgnosticDataRouteMatch,
|
|
3780
3757
|
requestContext: unknown,
|
|
3781
|
-
|
|
3758
|
+
dataStrategy: DataStrategyFunction | null,
|
|
3782
3759
|
skipLoaderErrorBubbling: boolean,
|
|
3783
3760
|
isRouteRequest: boolean
|
|
3784
3761
|
): Promise<Omit<StaticHandlerContext, "location" | "basename"> | Response> {
|
|
@@ -3805,7 +3782,7 @@ export function createStaticHandler(
|
|
|
3805
3782
|
matches,
|
|
3806
3783
|
isRouteRequest,
|
|
3807
3784
|
requestContext,
|
|
3808
|
-
|
|
3785
|
+
dataStrategy
|
|
3809
3786
|
);
|
|
3810
3787
|
result = results[actionMatch.route.id];
|
|
3811
3788
|
|
|
@@ -3877,7 +3854,7 @@ export function createStaticHandler(
|
|
|
3877
3854
|
loaderRequest,
|
|
3878
3855
|
matches,
|
|
3879
3856
|
requestContext,
|
|
3880
|
-
|
|
3857
|
+
dataStrategy,
|
|
3881
3858
|
skipLoaderErrorBubbling,
|
|
3882
3859
|
null,
|
|
3883
3860
|
[boundaryMatch.route.id, result]
|
|
@@ -3902,7 +3879,7 @@ export function createStaticHandler(
|
|
|
3902
3879
|
loaderRequest,
|
|
3903
3880
|
matches,
|
|
3904
3881
|
requestContext,
|
|
3905
|
-
|
|
3882
|
+
dataStrategy,
|
|
3906
3883
|
skipLoaderErrorBubbling,
|
|
3907
3884
|
null
|
|
3908
3885
|
);
|
|
@@ -3924,7 +3901,7 @@ export function createStaticHandler(
|
|
|
3924
3901
|
request: Request,
|
|
3925
3902
|
matches: AgnosticDataRouteMatch[],
|
|
3926
3903
|
requestContext: unknown,
|
|
3927
|
-
|
|
3904
|
+
dataStrategy: DataStrategyFunction | null,
|
|
3928
3905
|
skipLoaderErrorBubbling: boolean,
|
|
3929
3906
|
routeMatch: AgnosticDataRouteMatch | null,
|
|
3930
3907
|
pendingActionResult?: PendingActionResult
|
|
@@ -3987,7 +3964,7 @@ export function createStaticHandler(
|
|
|
3987
3964
|
matches,
|
|
3988
3965
|
isRouteRequest,
|
|
3989
3966
|
requestContext,
|
|
3990
|
-
|
|
3967
|
+
dataStrategy
|
|
3991
3968
|
);
|
|
3992
3969
|
|
|
3993
3970
|
if (request.signal.aborted) {
|
|
@@ -4033,10 +4010,10 @@ export function createStaticHandler(
|
|
|
4033
4010
|
matches: AgnosticDataRouteMatch[],
|
|
4034
4011
|
isRouteRequest: boolean,
|
|
4035
4012
|
requestContext: unknown,
|
|
4036
|
-
|
|
4013
|
+
dataStrategy: DataStrategyFunction | null
|
|
4037
4014
|
): Promise<Record<string, DataResult>> {
|
|
4038
4015
|
let results = await callDataStrategyImpl(
|
|
4039
|
-
|
|
4016
|
+
dataStrategy || defaultDataStrategy,
|
|
4040
4017
|
type,
|
|
4041
4018
|
null,
|
|
4042
4019
|
request,
|
|
@@ -4179,16 +4156,23 @@ function normalizeTo(
|
|
|
4179
4156
|
path.hash = location.hash;
|
|
4180
4157
|
}
|
|
4181
4158
|
|
|
4182
|
-
//
|
|
4183
|
-
if (
|
|
4184
|
-
|
|
4185
|
-
activeRouteMatch &&
|
|
4186
|
-
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4159
|
+
// Account for `?index` params when routing to the current location
|
|
4160
|
+
if ((to == null || to === "" || to === ".") && activeRouteMatch) {
|
|
4161
|
+
let nakedIndex = hasNakedIndexQuery(path.search);
|
|
4162
|
+
if (activeRouteMatch.route.index && !nakedIndex) {
|
|
4163
|
+
// Add one when we're targeting an index route
|
|
4164
|
+
path.search = path.search
|
|
4165
|
+
? path.search.replace(/^\?/, "?index&")
|
|
4166
|
+
: "?index";
|
|
4167
|
+
} else if (!activeRouteMatch.route.index && nakedIndex) {
|
|
4168
|
+
// Remove existing ones when we're not
|
|
4169
|
+
let params = new URLSearchParams(path.search);
|
|
4170
|
+
let indexValues = params.getAll("index");
|
|
4171
|
+
params.delete("index");
|
|
4172
|
+
indexValues.filter((v) => v).forEach((v) => params.append("index", v));
|
|
4173
|
+
let qs = params.toString();
|
|
4174
|
+
path.search = qs ? `?${qs}` : "";
|
|
4175
|
+
}
|
|
4192
4176
|
}
|
|
4193
4177
|
|
|
4194
4178
|
// If we're operating within a basename, prepend it to the pathname. If
|
|
@@ -4352,20 +4336,18 @@ function normalizeNavigateOptions(
|
|
|
4352
4336
|
return { path: createPath(parsedPath), submission };
|
|
4353
4337
|
}
|
|
4354
4338
|
|
|
4355
|
-
// Filter out all routes below any caught error as they aren't going to
|
|
4339
|
+
// Filter out all routes at/below any caught error as they aren't going to
|
|
4356
4340
|
// render so we don't need to load them
|
|
4357
4341
|
function getLoaderMatchesUntilBoundary(
|
|
4358
4342
|
matches: AgnosticDataRouteMatch[],
|
|
4359
|
-
boundaryId: string
|
|
4343
|
+
boundaryId: string,
|
|
4344
|
+
includeBoundary = false
|
|
4360
4345
|
) {
|
|
4361
|
-
let
|
|
4362
|
-
if (
|
|
4363
|
-
|
|
4364
|
-
if (index >= 0) {
|
|
4365
|
-
boundaryMatches = matches.slice(0, index);
|
|
4366
|
-
}
|
|
4346
|
+
let index = matches.findIndex((m) => m.route.id === boundaryId);
|
|
4347
|
+
if (index >= 0) {
|
|
4348
|
+
return matches.slice(0, includeBoundary ? index + 1 : index);
|
|
4367
4349
|
}
|
|
4368
|
-
return
|
|
4350
|
+
return matches;
|
|
4369
4351
|
}
|
|
4370
4352
|
|
|
4371
4353
|
function getMatchesToLoad(
|
|
@@ -4374,7 +4356,7 @@ function getMatchesToLoad(
|
|
|
4374
4356
|
matches: AgnosticDataRouteMatch[],
|
|
4375
4357
|
submission: Submission | undefined,
|
|
4376
4358
|
location: Location,
|
|
4377
|
-
|
|
4359
|
+
initialHydration: boolean,
|
|
4378
4360
|
skipActionErrorRevalidation: boolean,
|
|
4379
4361
|
isRevalidationRequired: boolean,
|
|
4380
4362
|
cancelledDeferredRoutes: string[],
|
|
@@ -4395,13 +4377,26 @@ function getMatchesToLoad(
|
|
|
4395
4377
|
let nextUrl = history.createURL(location);
|
|
4396
4378
|
|
|
4397
4379
|
// Pick navigation matches that are net-new or qualify for revalidation
|
|
4398
|
-
let
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4380
|
+
let boundaryMatches = matches;
|
|
4381
|
+
if (initialHydration && state.errors) {
|
|
4382
|
+
// On initial hydration, only consider matches up to _and including_ the boundary.
|
|
4383
|
+
// This is inclusive to handle cases where a server loader ran successfully,
|
|
4384
|
+
// a child server loader bubbled up to this route, but this route has
|
|
4385
|
+
// `clientLoader.hydrate` so we want to still run the `clientLoader` so that
|
|
4386
|
+
// we have a complete version of `loaderData`
|
|
4387
|
+
boundaryMatches = getLoaderMatchesUntilBoundary(
|
|
4388
|
+
matches,
|
|
4389
|
+
Object.keys(state.errors)[0],
|
|
4390
|
+
true
|
|
4391
|
+
);
|
|
4392
|
+
} else if (pendingActionResult && isErrorResult(pendingActionResult[1])) {
|
|
4393
|
+
// If an action threw an error, we call loaders up to, but not including the
|
|
4394
|
+
// boundary
|
|
4395
|
+
boundaryMatches = getLoaderMatchesUntilBoundary(
|
|
4396
|
+
matches,
|
|
4397
|
+
pendingActionResult[0]
|
|
4398
|
+
);
|
|
4399
|
+
}
|
|
4405
4400
|
|
|
4406
4401
|
// Don't revalidate loaders by default after action 4xx/5xx responses
|
|
4407
4402
|
// when the flag is enabled. They can still opt-into revalidation via
|
|
@@ -4423,15 +4418,8 @@ function getMatchesToLoad(
|
|
|
4423
4418
|
return false;
|
|
4424
4419
|
}
|
|
4425
4420
|
|
|
4426
|
-
if (
|
|
4427
|
-
|
|
4428
|
-
return true;
|
|
4429
|
-
}
|
|
4430
|
-
return (
|
|
4431
|
-
state.loaderData[route.id] === undefined &&
|
|
4432
|
-
// Don't re-run if the loader ran and threw an error
|
|
4433
|
-
(!state.errors || state.errors[route.id] === undefined)
|
|
4434
|
-
);
|
|
4421
|
+
if (initialHydration) {
|
|
4422
|
+
return shouldLoadRouteOnHydration(route, state.loaderData, state.errors);
|
|
4435
4423
|
}
|
|
4436
4424
|
|
|
4437
4425
|
// Always call the loader on new route instances and pending defer cancellations
|
|
@@ -4473,12 +4461,12 @@ function getMatchesToLoad(
|
|
|
4473
4461
|
let revalidatingFetchers: RevalidatingFetcher[] = [];
|
|
4474
4462
|
fetchLoadMatches.forEach((f, key) => {
|
|
4475
4463
|
// Don't revalidate:
|
|
4476
|
-
// - on initial
|
|
4464
|
+
// - on initial hydration (shouldn't be any fetchers then anyway)
|
|
4477
4465
|
// - if fetcher won't be present in the subsequent render
|
|
4478
4466
|
// - no longer matches the URL (v7_fetcherPersist=false)
|
|
4479
4467
|
// - was unmounted but persisted due to v7_fetcherPersist=true
|
|
4480
4468
|
if (
|
|
4481
|
-
|
|
4469
|
+
initialHydration ||
|
|
4482
4470
|
!matches.some((m) => m.route.id === f.routeId) ||
|
|
4483
4471
|
deletedFetchers.has(key)
|
|
4484
4472
|
) {
|
|
@@ -4558,6 +4546,38 @@ function getMatchesToLoad(
|
|
|
4558
4546
|
return [navigationMatches, revalidatingFetchers];
|
|
4559
4547
|
}
|
|
4560
4548
|
|
|
4549
|
+
function shouldLoadRouteOnHydration(
|
|
4550
|
+
route: AgnosticDataRouteObject,
|
|
4551
|
+
loaderData: RouteData | null | undefined,
|
|
4552
|
+
errors: RouteData | null | undefined
|
|
4553
|
+
) {
|
|
4554
|
+
// We dunno if we have a loader - gotta find out!
|
|
4555
|
+
if (route.lazy) {
|
|
4556
|
+
return true;
|
|
4557
|
+
}
|
|
4558
|
+
|
|
4559
|
+
// No loader, nothing to initialize
|
|
4560
|
+
if (!route.loader) {
|
|
4561
|
+
return false;
|
|
4562
|
+
}
|
|
4563
|
+
|
|
4564
|
+
let hasData = loaderData != null && loaderData[route.id] !== undefined;
|
|
4565
|
+
let hasError = errors != null && errors[route.id] !== undefined;
|
|
4566
|
+
|
|
4567
|
+
// Don't run if we error'd during SSR
|
|
4568
|
+
if (!hasData && hasError) {
|
|
4569
|
+
return false;
|
|
4570
|
+
}
|
|
4571
|
+
|
|
4572
|
+
// Explicitly opting-in to running on hydration
|
|
4573
|
+
if (typeof route.loader === "function" && route.loader.hydrate === true) {
|
|
4574
|
+
return true;
|
|
4575
|
+
}
|
|
4576
|
+
|
|
4577
|
+
// Otherwise, run if we're not yet initialized with anything
|
|
4578
|
+
return !hasData && !hasError;
|
|
4579
|
+
}
|
|
4580
|
+
|
|
4561
4581
|
function isNewLoader(
|
|
4562
4582
|
currentLoaderData: RouteData,
|
|
4563
4583
|
currentMatch: AgnosticDataRouteMatch,
|
|
@@ -4607,53 +4627,6 @@ function shouldRevalidateLoader(
|
|
|
4607
4627
|
return arg.defaultShouldRevalidate;
|
|
4608
4628
|
}
|
|
4609
4629
|
|
|
4610
|
-
/**
|
|
4611
|
-
* Idempotent utility to execute patchRoutesOnNavigation() to lazily load route
|
|
4612
|
-
* definitions and update the routes/routeManifest
|
|
4613
|
-
*/
|
|
4614
|
-
async function loadLazyRouteChildren(
|
|
4615
|
-
patchRoutesOnNavigationImpl: AgnosticPatchRoutesOnNavigationFunction,
|
|
4616
|
-
path: string,
|
|
4617
|
-
matches: AgnosticDataRouteMatch[],
|
|
4618
|
-
routes: AgnosticDataRouteObject[],
|
|
4619
|
-
manifest: RouteManifest,
|
|
4620
|
-
mapRouteProperties: MapRoutePropertiesFunction,
|
|
4621
|
-
pendingRouteChildren: Map<
|
|
4622
|
-
string,
|
|
4623
|
-
ReturnType<typeof patchRoutesOnNavigationImpl>
|
|
4624
|
-
>,
|
|
4625
|
-
signal: AbortSignal
|
|
4626
|
-
) {
|
|
4627
|
-
let key = [path, ...matches.map((m) => m.route.id)].join("-");
|
|
4628
|
-
try {
|
|
4629
|
-
let pending = pendingRouteChildren.get(key);
|
|
4630
|
-
if (!pending) {
|
|
4631
|
-
pending = patchRoutesOnNavigationImpl({
|
|
4632
|
-
path,
|
|
4633
|
-
matches,
|
|
4634
|
-
patch: (routeId, children) => {
|
|
4635
|
-
if (!signal.aborted) {
|
|
4636
|
-
patchRoutesImpl(
|
|
4637
|
-
routeId,
|
|
4638
|
-
children,
|
|
4639
|
-
routes,
|
|
4640
|
-
manifest,
|
|
4641
|
-
mapRouteProperties
|
|
4642
|
-
);
|
|
4643
|
-
}
|
|
4644
|
-
},
|
|
4645
|
-
});
|
|
4646
|
-
pendingRouteChildren.set(key, pending);
|
|
4647
|
-
}
|
|
4648
|
-
|
|
4649
|
-
if (pending && isPromise<AgnosticRouteObject[]>(pending)) {
|
|
4650
|
-
await pending;
|
|
4651
|
-
}
|
|
4652
|
-
} finally {
|
|
4653
|
-
pendingRouteChildren.delete(key);
|
|
4654
|
-
}
|
|
4655
|
-
}
|
|
4656
|
-
|
|
4657
4630
|
function patchRoutesImpl(
|
|
4658
4631
|
routeId: string | null,
|
|
4659
4632
|
children: AgnosticRouteObject[],
|
|
@@ -4661,32 +4634,79 @@ function patchRoutesImpl(
|
|
|
4661
4634
|
manifest: RouteManifest,
|
|
4662
4635
|
mapRouteProperties: MapRoutePropertiesFunction
|
|
4663
4636
|
) {
|
|
4637
|
+
let childrenToPatch: AgnosticDataRouteObject[];
|
|
4664
4638
|
if (routeId) {
|
|
4665
4639
|
let route = manifest[routeId];
|
|
4666
4640
|
invariant(
|
|
4667
4641
|
route,
|
|
4668
4642
|
`No route found to patch children into: routeId = ${routeId}`
|
|
4669
4643
|
);
|
|
4670
|
-
|
|
4671
|
-
children
|
|
4672
|
-
mapRouteProperties,
|
|
4673
|
-
[routeId, "patch", String(route.children?.length || "0")],
|
|
4674
|
-
manifest
|
|
4675
|
-
);
|
|
4676
|
-
if (route.children) {
|
|
4677
|
-
route.children.push(...dataChildren);
|
|
4678
|
-
} else {
|
|
4679
|
-
route.children = dataChildren;
|
|
4644
|
+
if (!route.children) {
|
|
4645
|
+
route.children = [];
|
|
4680
4646
|
}
|
|
4647
|
+
childrenToPatch = route.children;
|
|
4681
4648
|
} else {
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4649
|
+
childrenToPatch = routesToUse;
|
|
4650
|
+
}
|
|
4651
|
+
|
|
4652
|
+
// Don't patch in routes we already know about so that `patch` is idempotent
|
|
4653
|
+
// to simplify user-land code. This is useful because we re-call the
|
|
4654
|
+
// `patchRoutesOnNavigation` function for matched routes with params.
|
|
4655
|
+
let uniqueChildren = children.filter(
|
|
4656
|
+
(newRoute) =>
|
|
4657
|
+
!childrenToPatch.some((existingRoute) =>
|
|
4658
|
+
isSameRoute(newRoute, existingRoute)
|
|
4659
|
+
)
|
|
4660
|
+
);
|
|
4661
|
+
|
|
4662
|
+
let newRoutes = convertRoutesToDataRoutes(
|
|
4663
|
+
uniqueChildren,
|
|
4664
|
+
mapRouteProperties,
|
|
4665
|
+
[routeId || "_", "patch", String(childrenToPatch?.length || "0")],
|
|
4666
|
+
manifest
|
|
4667
|
+
);
|
|
4668
|
+
|
|
4669
|
+
childrenToPatch.push(...newRoutes);
|
|
4670
|
+
}
|
|
4671
|
+
|
|
4672
|
+
function isSameRoute(
|
|
4673
|
+
newRoute: AgnosticRouteObject,
|
|
4674
|
+
existingRoute: AgnosticRouteObject
|
|
4675
|
+
): boolean {
|
|
4676
|
+
// Most optimal check is by id
|
|
4677
|
+
if (
|
|
4678
|
+
"id" in newRoute &&
|
|
4679
|
+
"id" in existingRoute &&
|
|
4680
|
+
newRoute.id === existingRoute.id
|
|
4681
|
+
) {
|
|
4682
|
+
return true;
|
|
4683
|
+
}
|
|
4684
|
+
|
|
4685
|
+
// Second is by pathing differences
|
|
4686
|
+
if (
|
|
4687
|
+
!(
|
|
4688
|
+
newRoute.index === existingRoute.index &&
|
|
4689
|
+
newRoute.path === existingRoute.path &&
|
|
4690
|
+
newRoute.caseSensitive === existingRoute.caseSensitive
|
|
4691
|
+
)
|
|
4692
|
+
) {
|
|
4693
|
+
return false;
|
|
4689
4694
|
}
|
|
4695
|
+
|
|
4696
|
+
// Pathless layout routes are trickier since we need to check children.
|
|
4697
|
+
// If they have no children then they're the same as far as we can tell
|
|
4698
|
+
if (
|
|
4699
|
+
(!newRoute.children || newRoute.children.length === 0) &&
|
|
4700
|
+
(!existingRoute.children || existingRoute.children.length === 0)
|
|
4701
|
+
) {
|
|
4702
|
+
return true;
|
|
4703
|
+
}
|
|
4704
|
+
|
|
4705
|
+
// Otherwise, we look to see if every child in the new route is already
|
|
4706
|
+
// represented in the existing route's children
|
|
4707
|
+
return newRoute.children!.every((aChild, i) =>
|
|
4708
|
+
existingRoute.children?.some((bChild) => isSameRoute(aChild, bChild))
|
|
4709
|
+
);
|
|
4690
4710
|
}
|
|
4691
4711
|
|
|
4692
4712
|
/**
|
|
@@ -5038,7 +5058,7 @@ async function convertDataStrategyResultToDataResult(
|
|
|
5038
5058
|
};
|
|
5039
5059
|
}
|
|
5040
5060
|
|
|
5041
|
-
// Convert thrown
|
|
5061
|
+
// Convert thrown data() to ErrorResponse instances
|
|
5042
5062
|
result = new ErrorResponseImpl(
|
|
5043
5063
|
result.init?.status || 500,
|
|
5044
5064
|
undefined,
|
|
@@ -5310,7 +5330,6 @@ function processRouteLoaderData(
|
|
|
5310
5330
|
function processLoaderData(
|
|
5311
5331
|
state: RouterState,
|
|
5312
5332
|
matches: AgnosticDataRouteMatch[],
|
|
5313
|
-
matchesToLoad: AgnosticDataRouteMatch[],
|
|
5314
5333
|
results: Record<string, DataResult>,
|
|
5315
5334
|
pendingActionResult: PendingActionResult | undefined,
|
|
5316
5335
|
revalidatingFetchers: RevalidatingFetcher[],
|
|
@@ -5477,7 +5496,7 @@ function getInternalRouterError(
|
|
|
5477
5496
|
statusText = "Bad Request";
|
|
5478
5497
|
if (type === "route-discovery") {
|
|
5479
5498
|
errorMessage =
|
|
5480
|
-
`Unable to match URL "${pathname}" - the \`
|
|
5499
|
+
`Unable to match URL "${pathname}" - the \`patchRoutesOnNavigation()\` ` +
|
|
5481
5500
|
`function threw the following error:\n${message}`;
|
|
5482
5501
|
} else if (method && pathname && routeId) {
|
|
5483
5502
|
errorMessage =
|