@remix-run/router 1.13.1 → 1.14.0-pre.1
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 +187 -0
- package/dist/index.d.ts +1 -1
- package/dist/router.cjs.js +117 -39
- package/dist/router.cjs.js.map +1 -1
- package/dist/router.d.ts +16 -0
- package/dist/router.js +109 -39
- package/dist/router.js.map +1 -1
- package/dist/router.umd.js +117 -39
- 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 +5 -2
- package/index.ts +1 -1
- package/package.json +1 -1
- package/router.ts +131 -21
- package/utils.ts +27 -5
package/dist/utils.d.ts
CHANGED
|
@@ -135,9 +135,11 @@ type DataFunctionValue = Response | NonNullable<unknown> | null;
|
|
|
135
135
|
/**
|
|
136
136
|
* Route loader function signature
|
|
137
137
|
*/
|
|
138
|
-
export
|
|
138
|
+
export type LoaderFunction<Context = any> = {
|
|
139
139
|
(args: LoaderFunctionArgs<Context>): Promise<DataFunctionValue> | DataFunctionValue;
|
|
140
|
-
}
|
|
140
|
+
} & {
|
|
141
|
+
hydrate?: boolean;
|
|
142
|
+
};
|
|
141
143
|
/**
|
|
142
144
|
* Route action function signature
|
|
143
145
|
*/
|
|
@@ -399,6 +401,7 @@ export declare function resolvePath(to: To, fromPathname?: string): Path;
|
|
|
399
401
|
* </Route>
|
|
400
402
|
*/
|
|
401
403
|
export declare function getPathContributingMatches<T extends AgnosticRouteMatch = AgnosticRouteMatch>(matches: T[]): T[];
|
|
404
|
+
export declare function getResolveToMatches<T extends AgnosticRouteMatch = AgnosticRouteMatch>(matches: T[], v7_relativeSplatPath: boolean): string[];
|
|
402
405
|
/**
|
|
403
406
|
* @private
|
|
404
407
|
*/
|
package/index.ts
CHANGED
|
@@ -87,7 +87,7 @@ export {
|
|
|
87
87
|
ErrorResponseImpl as UNSAFE_ErrorResponseImpl,
|
|
88
88
|
convertRoutesToDataRoutes as UNSAFE_convertRoutesToDataRoutes,
|
|
89
89
|
convertRouteMatchToUiMatch as UNSAFE_convertRouteMatchToUiMatch,
|
|
90
|
-
|
|
90
|
+
getResolveToMatches as UNSAFE_getResolveToMatches,
|
|
91
91
|
} from "./utils";
|
|
92
92
|
|
|
93
93
|
export {
|
package/package.json
CHANGED
package/router.ts
CHANGED
|
@@ -40,6 +40,7 @@ import {
|
|
|
40
40
|
convertRouteMatchToUiMatch,
|
|
41
41
|
convertRoutesToDataRoutes,
|
|
42
42
|
getPathContributingMatches,
|
|
43
|
+
getResolveToMatches,
|
|
43
44
|
immutableRouteKeys,
|
|
44
45
|
isRouteErrorResponse,
|
|
45
46
|
joinPaths,
|
|
@@ -64,6 +65,14 @@ export interface Router {
|
|
|
64
65
|
*/
|
|
65
66
|
get basename(): RouterInit["basename"];
|
|
66
67
|
|
|
68
|
+
/**
|
|
69
|
+
* @internal
|
|
70
|
+
* PRIVATE - DO NOT USE
|
|
71
|
+
*
|
|
72
|
+
* Return the future config for the router
|
|
73
|
+
*/
|
|
74
|
+
get future(): FutureConfig;
|
|
75
|
+
|
|
67
76
|
/**
|
|
68
77
|
* @internal
|
|
69
78
|
* PRIVATE - DO NOT USE
|
|
@@ -345,7 +354,9 @@ export type HydrationState = Partial<
|
|
|
345
354
|
export interface FutureConfig {
|
|
346
355
|
v7_fetcherPersist: boolean;
|
|
347
356
|
v7_normalizeFormMethod: boolean;
|
|
357
|
+
v7_partialHydration: boolean;
|
|
348
358
|
v7_prependBasename: boolean;
|
|
359
|
+
v7_relativeSplatPath: boolean;
|
|
349
360
|
}
|
|
350
361
|
|
|
351
362
|
/**
|
|
@@ -769,7 +780,9 @@ export function createRouter(init: RouterInit): Router {
|
|
|
769
780
|
let future: FutureConfig = {
|
|
770
781
|
v7_fetcherPersist: false,
|
|
771
782
|
v7_normalizeFormMethod: false,
|
|
783
|
+
v7_partialHydration: false,
|
|
772
784
|
v7_prependBasename: false,
|
|
785
|
+
v7_relativeSplatPath: false,
|
|
773
786
|
...init.future,
|
|
774
787
|
};
|
|
775
788
|
// Cleanup function for history
|
|
@@ -804,12 +817,34 @@ export function createRouter(init: RouterInit): Router {
|
|
|
804
817
|
initialErrors = { [route.id]: error };
|
|
805
818
|
}
|
|
806
819
|
|
|
807
|
-
let initialized
|
|
820
|
+
let initialized: boolean;
|
|
821
|
+
let hasLazyRoutes = initialMatches.some((m) => m.route.lazy);
|
|
822
|
+
let hasLoaders = initialMatches.some((m) => m.route.loader);
|
|
823
|
+
if (hasLazyRoutes) {
|
|
808
824
|
// All initialMatches need to be loaded before we're ready. If we have lazy
|
|
809
825
|
// functions around still then we'll need to run them in initialize()
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
826
|
+
initialized = false;
|
|
827
|
+
} else if (!hasLoaders) {
|
|
828
|
+
// If we've got no loaders to run, then we're good to go
|
|
829
|
+
initialized = true;
|
|
830
|
+
} else if (future.v7_partialHydration) {
|
|
831
|
+
// If partial hydration is enabled, we're initialized so long as we were
|
|
832
|
+
// provided with hydrationData for every route with a loader, and no loaders
|
|
833
|
+
// were marked for explicit hydration
|
|
834
|
+
let loaderData = init.hydrationData ? init.hydrationData.loaderData : null;
|
|
835
|
+
let errors = init.hydrationData ? init.hydrationData.errors : null;
|
|
836
|
+
initialized = initialMatches.every(
|
|
837
|
+
(m) =>
|
|
838
|
+
m.route.loader &&
|
|
839
|
+
m.route.loader.hydrate !== true &&
|
|
840
|
+
((loaderData && loaderData[m.route.id] !== undefined) ||
|
|
841
|
+
(errors && errors[m.route.id] !== undefined))
|
|
842
|
+
);
|
|
843
|
+
} else {
|
|
844
|
+
// Without partial hydration - we're initialized if we were provided any
|
|
845
|
+
// hydrationData - which is expected to be complete
|
|
846
|
+
initialized = init.hydrationData != null;
|
|
847
|
+
}
|
|
813
848
|
|
|
814
849
|
let router: Router;
|
|
815
850
|
let state: RouterState = {
|
|
@@ -991,7 +1026,9 @@ export function createRouter(init: RouterInit): Router {
|
|
|
991
1026
|
// resolved prior to router creation since we can't go into a fallbackElement
|
|
992
1027
|
// UI for SSR'd apps
|
|
993
1028
|
if (!state.initialized) {
|
|
994
|
-
startNavigation(HistoryAction.Pop, state.location
|
|
1029
|
+
startNavigation(HistoryAction.Pop, state.location, {
|
|
1030
|
+
initialHydration: true,
|
|
1031
|
+
});
|
|
995
1032
|
}
|
|
996
1033
|
|
|
997
1034
|
return router;
|
|
@@ -1231,6 +1268,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
1231
1268
|
basename,
|
|
1232
1269
|
future.v7_prependBasename,
|
|
1233
1270
|
to,
|
|
1271
|
+
future.v7_relativeSplatPath,
|
|
1234
1272
|
opts?.fromRouteId,
|
|
1235
1273
|
opts?.relative
|
|
1236
1274
|
);
|
|
@@ -1363,6 +1401,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
1363
1401
|
historyAction: HistoryAction,
|
|
1364
1402
|
location: Location,
|
|
1365
1403
|
opts?: {
|
|
1404
|
+
initialHydration?: boolean;
|
|
1366
1405
|
submission?: Submission;
|
|
1367
1406
|
fetcherSubmission?: Submission;
|
|
1368
1407
|
overrideNavigation?: Navigation;
|
|
@@ -1487,6 +1526,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
1487
1526
|
opts && opts.submission,
|
|
1488
1527
|
opts && opts.fetcherSubmission,
|
|
1489
1528
|
opts && opts.replace,
|
|
1529
|
+
opts && opts.initialHydration === true,
|
|
1490
1530
|
flushSync,
|
|
1491
1531
|
pendingActionData,
|
|
1492
1532
|
pendingError
|
|
@@ -1545,7 +1585,8 @@ export function createRouter(init: RouterInit): Router {
|
|
|
1545
1585
|
matches,
|
|
1546
1586
|
manifest,
|
|
1547
1587
|
mapRouteProperties,
|
|
1548
|
-
basename
|
|
1588
|
+
basename,
|
|
1589
|
+
future.v7_relativeSplatPath
|
|
1549
1590
|
);
|
|
1550
1591
|
|
|
1551
1592
|
if (request.signal.aborted) {
|
|
@@ -1607,6 +1648,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
1607
1648
|
submission?: Submission,
|
|
1608
1649
|
fetcherSubmission?: Submission,
|
|
1609
1650
|
replace?: boolean,
|
|
1651
|
+
initialHydration?: boolean,
|
|
1610
1652
|
flushSync?: boolean,
|
|
1611
1653
|
pendingActionData?: RouteData,
|
|
1612
1654
|
pendingError?: RouteData
|
|
@@ -1629,6 +1671,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
1629
1671
|
matches,
|
|
1630
1672
|
activeSubmission,
|
|
1631
1673
|
location,
|
|
1674
|
+
future.v7_partialHydration && initialHydration === true,
|
|
1632
1675
|
isRevalidationRequired,
|
|
1633
1676
|
cancelledDeferredRoutes,
|
|
1634
1677
|
cancelledFetcherLoads,
|
|
@@ -1674,7 +1717,12 @@ export function createRouter(init: RouterInit): Router {
|
|
|
1674
1717
|
// state. If not, we need to switch to our loading state and load data,
|
|
1675
1718
|
// preserving any new action data or existing action data (in the case of
|
|
1676
1719
|
// a revalidation interrupting an actionReload)
|
|
1677
|
-
|
|
1720
|
+
// If we have partialHydration enabled, then don't update the state for the
|
|
1721
|
+
// initial data load since iot's not a "navigation"
|
|
1722
|
+
if (
|
|
1723
|
+
!isUninterruptedRevalidation &&
|
|
1724
|
+
(!future.v7_partialHydration || !initialHydration)
|
|
1725
|
+
) {
|
|
1678
1726
|
revalidatingFetchers.forEach((rf) => {
|
|
1679
1727
|
let fetcher = state.fetchers.get(rf.key);
|
|
1680
1728
|
let revalidatingFetcher = getLoadingFetcher(
|
|
@@ -1824,6 +1872,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
1824
1872
|
basename,
|
|
1825
1873
|
future.v7_prependBasename,
|
|
1826
1874
|
href,
|
|
1875
|
+
future.v7_relativeSplatPath,
|
|
1827
1876
|
routeId,
|
|
1828
1877
|
opts?.relative
|
|
1829
1878
|
);
|
|
@@ -1930,7 +1979,8 @@ export function createRouter(init: RouterInit): Router {
|
|
|
1930
1979
|
requestMatches,
|
|
1931
1980
|
manifest,
|
|
1932
1981
|
mapRouteProperties,
|
|
1933
|
-
basename
|
|
1982
|
+
basename,
|
|
1983
|
+
future.v7_relativeSplatPath
|
|
1934
1984
|
);
|
|
1935
1985
|
|
|
1936
1986
|
if (fetchRequest.signal.aborted) {
|
|
@@ -2003,6 +2053,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
2003
2053
|
matches,
|
|
2004
2054
|
submission,
|
|
2005
2055
|
nextLocation,
|
|
2056
|
+
false,
|
|
2006
2057
|
isRevalidationRequired,
|
|
2007
2058
|
cancelledDeferredRoutes,
|
|
2008
2059
|
cancelledFetcherLoads,
|
|
@@ -2173,7 +2224,8 @@ export function createRouter(init: RouterInit): Router {
|
|
|
2173
2224
|
matches,
|
|
2174
2225
|
manifest,
|
|
2175
2226
|
mapRouteProperties,
|
|
2176
|
-
basename
|
|
2227
|
+
basename,
|
|
2228
|
+
future.v7_relativeSplatPath
|
|
2177
2229
|
);
|
|
2178
2230
|
|
|
2179
2231
|
// Deferred isn't supported for fetcher loads, await everything and treat it
|
|
@@ -2369,7 +2421,8 @@ export function createRouter(init: RouterInit): Router {
|
|
|
2369
2421
|
matches,
|
|
2370
2422
|
manifest,
|
|
2371
2423
|
mapRouteProperties,
|
|
2372
|
-
basename
|
|
2424
|
+
basename,
|
|
2425
|
+
future.v7_relativeSplatPath
|
|
2373
2426
|
)
|
|
2374
2427
|
),
|
|
2375
2428
|
...fetchersToLoad.map((f) => {
|
|
@@ -2381,7 +2434,8 @@ export function createRouter(init: RouterInit): Router {
|
|
|
2381
2434
|
f.matches,
|
|
2382
2435
|
manifest,
|
|
2383
2436
|
mapRouteProperties,
|
|
2384
|
-
basename
|
|
2437
|
+
basename,
|
|
2438
|
+
future.v7_relativeSplatPath
|
|
2385
2439
|
);
|
|
2386
2440
|
} else {
|
|
2387
2441
|
let error: ErrorResult = {
|
|
@@ -2723,6 +2777,9 @@ export function createRouter(init: RouterInit): Router {
|
|
|
2723
2777
|
get basename() {
|
|
2724
2778
|
return basename;
|
|
2725
2779
|
},
|
|
2780
|
+
get future() {
|
|
2781
|
+
return future;
|
|
2782
|
+
},
|
|
2726
2783
|
get state() {
|
|
2727
2784
|
return state;
|
|
2728
2785
|
},
|
|
@@ -2764,6 +2821,13 @@ export function createRouter(init: RouterInit): Router {
|
|
|
2764
2821
|
|
|
2765
2822
|
export const UNSAFE_DEFERRED_SYMBOL = Symbol("deferred");
|
|
2766
2823
|
|
|
2824
|
+
/**
|
|
2825
|
+
* Future flags to toggle new feature behavior
|
|
2826
|
+
*/
|
|
2827
|
+
export interface StaticHandlerFutureConfig {
|
|
2828
|
+
v7_relativeSplatPath: boolean;
|
|
2829
|
+
}
|
|
2830
|
+
|
|
2767
2831
|
export interface CreateStaticHandlerOptions {
|
|
2768
2832
|
basename?: string;
|
|
2769
2833
|
/**
|
|
@@ -2771,6 +2835,7 @@ export interface CreateStaticHandlerOptions {
|
|
|
2771
2835
|
*/
|
|
2772
2836
|
detectErrorBoundary?: DetectErrorBoundaryFunction;
|
|
2773
2837
|
mapRouteProperties?: MapRoutePropertiesFunction;
|
|
2838
|
+
future?: Partial<StaticHandlerFutureConfig>;
|
|
2774
2839
|
}
|
|
2775
2840
|
|
|
2776
2841
|
export function createStaticHandler(
|
|
@@ -2796,6 +2861,11 @@ export function createStaticHandler(
|
|
|
2796
2861
|
} else {
|
|
2797
2862
|
mapRouteProperties = defaultMapRouteProperties;
|
|
2798
2863
|
}
|
|
2864
|
+
// Config driven behavior flags
|
|
2865
|
+
let future: StaticHandlerFutureConfig = {
|
|
2866
|
+
v7_relativeSplatPath: false,
|
|
2867
|
+
...(opts ? opts.future : null),
|
|
2868
|
+
};
|
|
2799
2869
|
|
|
2800
2870
|
let dataRoutes = convertRoutesToDataRoutes(
|
|
2801
2871
|
routes,
|
|
@@ -3058,6 +3128,7 @@ export function createStaticHandler(
|
|
|
3058
3128
|
manifest,
|
|
3059
3129
|
mapRouteProperties,
|
|
3060
3130
|
basename,
|
|
3131
|
+
future.v7_relativeSplatPath,
|
|
3061
3132
|
{ isStaticRequest: true, isRouteRequest, requestContext }
|
|
3062
3133
|
);
|
|
3063
3134
|
|
|
@@ -3226,6 +3297,7 @@ export function createStaticHandler(
|
|
|
3226
3297
|
manifest,
|
|
3227
3298
|
mapRouteProperties,
|
|
3228
3299
|
basename,
|
|
3300
|
+
future.v7_relativeSplatPath,
|
|
3229
3301
|
{ isStaticRequest: true, isRouteRequest, requestContext }
|
|
3230
3302
|
)
|
|
3231
3303
|
),
|
|
@@ -3316,6 +3388,7 @@ function normalizeTo(
|
|
|
3316
3388
|
basename: string,
|
|
3317
3389
|
prependBasename: boolean,
|
|
3318
3390
|
to: To | null,
|
|
3391
|
+
v7_relativeSplatPath: boolean,
|
|
3319
3392
|
fromRouteId?: string,
|
|
3320
3393
|
relative?: RelativeRoutingType
|
|
3321
3394
|
) {
|
|
@@ -3340,7 +3413,7 @@ function normalizeTo(
|
|
|
3340
3413
|
// Resolve the relative path
|
|
3341
3414
|
let path = resolveTo(
|
|
3342
3415
|
to ? to : ".",
|
|
3343
|
-
|
|
3416
|
+
getResolveToMatches(contextualMatches, v7_relativeSplatPath),
|
|
3344
3417
|
stripBasename(location.pathname, basename) || location.pathname,
|
|
3345
3418
|
relative === "path"
|
|
3346
3419
|
);
|
|
@@ -3548,6 +3621,7 @@ function getMatchesToLoad(
|
|
|
3548
3621
|
matches: AgnosticDataRouteMatch[],
|
|
3549
3622
|
submission: Submission | undefined,
|
|
3550
3623
|
location: Location,
|
|
3624
|
+
isInitialLoad: boolean,
|
|
3551
3625
|
isRevalidationRequired: boolean,
|
|
3552
3626
|
cancelledDeferredRoutes: string[],
|
|
3553
3627
|
cancelledFetcherLoads: string[],
|
|
@@ -3573,10 +3647,17 @@ function getMatchesToLoad(
|
|
|
3573
3647
|
let boundaryMatches = getLoaderMatchesUntilBoundary(matches, boundaryId);
|
|
3574
3648
|
|
|
3575
3649
|
let navigationMatches = boundaryMatches.filter((match, index) => {
|
|
3650
|
+
if (isInitialLoad) {
|
|
3651
|
+
// On initial hydration we don't do any shouldRevalidate stuff - we just
|
|
3652
|
+
// call the unhydrated loaders
|
|
3653
|
+
return isUnhydratedRoute(state, match.route);
|
|
3654
|
+
}
|
|
3655
|
+
|
|
3576
3656
|
if (match.route.lazy) {
|
|
3577
3657
|
// We haven't loaded this route yet so we don't know if it's got a loader!
|
|
3578
3658
|
return true;
|
|
3579
3659
|
}
|
|
3660
|
+
|
|
3580
3661
|
if (match.route.loader == null) {
|
|
3581
3662
|
return false;
|
|
3582
3663
|
}
|
|
@@ -3618,8 +3699,13 @@ function getMatchesToLoad(
|
|
|
3618
3699
|
// Pick fetcher.loads that need to be revalidated
|
|
3619
3700
|
let revalidatingFetchers: RevalidatingFetcher[] = [];
|
|
3620
3701
|
fetchLoadMatches.forEach((f, key) => {
|
|
3621
|
-
// Don't revalidate
|
|
3702
|
+
// Don't revalidate:
|
|
3703
|
+
// - on initial load (shouldn't be any fetchers then anyway)
|
|
3704
|
+
// - if fetcher won't be present in the subsequent render
|
|
3705
|
+
// - no longer matches the URL (v7_fetcherPersist=false)
|
|
3706
|
+
// - was unmounted but persisted due to v7_fetcherPersist=true
|
|
3622
3707
|
if (
|
|
3708
|
+
isInitialLoad ||
|
|
3623
3709
|
!matches.some((m) => m.route.id === f.routeId) ||
|
|
3624
3710
|
deletedFetchers.has(key)
|
|
3625
3711
|
) {
|
|
@@ -3695,6 +3781,23 @@ function getMatchesToLoad(
|
|
|
3695
3781
|
return [navigationMatches, revalidatingFetchers];
|
|
3696
3782
|
}
|
|
3697
3783
|
|
|
3784
|
+
// Is this route unhydrated (when v7_partialHydration=true) such that we need
|
|
3785
|
+
// to call it's loader on the initial router creation
|
|
3786
|
+
function isUnhydratedRoute(state: RouterState, route: AgnosticDataRouteObject) {
|
|
3787
|
+
if (!route.loader) {
|
|
3788
|
+
return false;
|
|
3789
|
+
}
|
|
3790
|
+
if (route.loader.hydrate) {
|
|
3791
|
+
return true;
|
|
3792
|
+
}
|
|
3793
|
+
return (
|
|
3794
|
+
state.loaderData[route.id] === undefined &&
|
|
3795
|
+
(!state.errors ||
|
|
3796
|
+
// Loader ran but errored - don't re-run
|
|
3797
|
+
state.errors[route.id] === undefined)
|
|
3798
|
+
);
|
|
3799
|
+
}
|
|
3800
|
+
|
|
3698
3801
|
function isNewLoader(
|
|
3699
3802
|
currentLoaderData: RouteData,
|
|
3700
3803
|
currentMatch: AgnosticDataRouteMatch,
|
|
@@ -3830,6 +3933,7 @@ async function callLoaderOrAction(
|
|
|
3830
3933
|
manifest: RouteManifest,
|
|
3831
3934
|
mapRouteProperties: MapRoutePropertiesFunction,
|
|
3832
3935
|
basename: string,
|
|
3936
|
+
v7_relativeSplatPath: boolean,
|
|
3833
3937
|
opts: {
|
|
3834
3938
|
isStaticRequest?: boolean;
|
|
3835
3939
|
isRouteRequest?: boolean;
|
|
@@ -3943,7 +4047,8 @@ async function callLoaderOrAction(
|
|
|
3943
4047
|
matches.slice(0, matches.indexOf(match) + 1),
|
|
3944
4048
|
basename,
|
|
3945
4049
|
true,
|
|
3946
|
-
location
|
|
4050
|
+
location,
|
|
4051
|
+
v7_relativeSplatPath
|
|
3947
4052
|
);
|
|
3948
4053
|
} else if (!opts.isStaticRequest) {
|
|
3949
4054
|
// Strip off the protocol+origin for same-origin + same-basename absolute
|
|
@@ -3990,13 +4095,18 @@ async function callLoaderOrAction(
|
|
|
3990
4095
|
}
|
|
3991
4096
|
|
|
3992
4097
|
let data: any;
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4098
|
+
|
|
4099
|
+
try {
|
|
4100
|
+
let contentType = result.headers.get("Content-Type");
|
|
4101
|
+
// Check between word boundaries instead of startsWith() due to the last
|
|
4102
|
+
// paragraph of https://httpwg.org/specs/rfc9110.html#field.content-type
|
|
4103
|
+
if (contentType && /\bapplication\/json\b/.test(contentType)) {
|
|
4104
|
+
data = await result.json();
|
|
4105
|
+
} else {
|
|
4106
|
+
data = await result.text();
|
|
4107
|
+
}
|
|
4108
|
+
} catch (e) {
|
|
4109
|
+
return { type: ResultType.error, error: e };
|
|
4000
4110
|
}
|
|
4001
4111
|
|
|
4002
4112
|
if (resultType === ResultType.error) {
|
package/utils.ts
CHANGED
|
@@ -169,11 +169,11 @@ type DataFunctionValue = Response | NonNullable<unknown> | null;
|
|
|
169
169
|
/**
|
|
170
170
|
* Route loader function signature
|
|
171
171
|
*/
|
|
172
|
-
export
|
|
172
|
+
export type LoaderFunction<Context = any> = {
|
|
173
173
|
(args: LoaderFunctionArgs<Context>):
|
|
174
174
|
| Promise<DataFunctionValue>
|
|
175
175
|
| DataFunctionValue;
|
|
176
|
-
}
|
|
176
|
+
} & { hydrate?: boolean };
|
|
177
177
|
|
|
178
178
|
/**
|
|
179
179
|
* Route action function signature
|
|
@@ -1145,6 +1145,25 @@ export function getPathContributingMatches<
|
|
|
1145
1145
|
);
|
|
1146
1146
|
}
|
|
1147
1147
|
|
|
1148
|
+
// Return the array of pathnames for the current route matches - used to
|
|
1149
|
+
// generate the routePathnames input for resolveTo()
|
|
1150
|
+
export function getResolveToMatches<
|
|
1151
|
+
T extends AgnosticRouteMatch = AgnosticRouteMatch
|
|
1152
|
+
>(matches: T[], v7_relativeSplatPath: boolean) {
|
|
1153
|
+
let pathMatches = getPathContributingMatches(matches);
|
|
1154
|
+
|
|
1155
|
+
// When v7_relativeSplatPath is enabled, use the full pathname for the leaf
|
|
1156
|
+
// match so we include splat values for "." links. See:
|
|
1157
|
+
// https://github.com/remix-run/react-router/issues/11052#issuecomment-1836589329
|
|
1158
|
+
if (v7_relativeSplatPath) {
|
|
1159
|
+
return pathMatches.map((match, idx) =>
|
|
1160
|
+
idx === matches.length - 1 ? match.pathname : match.pathnameBase
|
|
1161
|
+
);
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
return pathMatches.map((match) => match.pathnameBase);
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1148
1167
|
/**
|
|
1149
1168
|
* @private
|
|
1150
1169
|
*/
|
|
@@ -1191,9 +1210,12 @@ export function resolveTo(
|
|
|
1191
1210
|
if (toPathname == null) {
|
|
1192
1211
|
from = locationPathname;
|
|
1193
1212
|
} else if (isPathRelative) {
|
|
1194
|
-
let fromSegments =
|
|
1195
|
-
.
|
|
1196
|
-
|
|
1213
|
+
let fromSegments =
|
|
1214
|
+
routePathnames.length === 0
|
|
1215
|
+
? []
|
|
1216
|
+
: routePathnames[routePathnames.length - 1]
|
|
1217
|
+
.replace(/^\//, "")
|
|
1218
|
+
.split("/");
|
|
1197
1219
|
|
|
1198
1220
|
if (toPathname.startsWith("..")) {
|
|
1199
1221
|
let toSegments = toPathname.split("/");
|