@remix-run/router 1.19.1 → 1.19.2
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 +17 -0
- package/dist/index.d.ts +1 -1
- package/dist/router.cjs.js +246 -163
- package/dist/router.cjs.js.map +1 -1
- package/dist/router.js +241 -158
- package/dist/router.js.map +1 -1
- package/dist/router.umd.js +246 -163
- 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 +10 -9
- package/index.ts +1 -1
- package/package.json +1 -1
- package/router.ts +334 -229
- package/utils.ts +12 -11
package/dist/router.umd.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @remix-run/router v1.19.
|
|
2
|
+
* @remix-run/router v1.19.2
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -579,10 +579,6 @@
|
|
|
579
579
|
* Result from a loader or action - potentially successful or unsuccessful
|
|
580
580
|
*/
|
|
581
581
|
|
|
582
|
-
/**
|
|
583
|
-
* Result from a loader or action called via dataStrategy
|
|
584
|
-
*/
|
|
585
|
-
|
|
586
582
|
/**
|
|
587
583
|
* Users can specify either lowercase or uppercase form methods on `<Form>`,
|
|
588
584
|
* useSubmit(), `<fetcher.Form>`, etc.
|
|
@@ -648,6 +644,9 @@
|
|
|
648
644
|
*
|
|
649
645
|
* @deprecated Use `mapRouteProperties` instead
|
|
650
646
|
*/
|
|
647
|
+
/**
|
|
648
|
+
* Result from a loader or action called via dataStrategy
|
|
649
|
+
*/
|
|
651
650
|
/**
|
|
652
651
|
* Function provided by the framework-aware layers to set any framework-specific
|
|
653
652
|
* properties from framework-agnostic properties
|
|
@@ -1928,7 +1927,7 @@
|
|
|
1928
1927
|
|
|
1929
1928
|
// Flag to ignore the next history update, so we can revert the URL change on
|
|
1930
1929
|
// a POP navigation that was blocked by the user without touching router state
|
|
1931
|
-
let
|
|
1930
|
+
let unblockBlockerHistoryUpdate = undefined;
|
|
1932
1931
|
|
|
1933
1932
|
// Initialize the router, all side effects should be kicked off from here.
|
|
1934
1933
|
// Implemented as a Fluent API for ease of:
|
|
@@ -1944,8 +1943,9 @@
|
|
|
1944
1943
|
} = _ref;
|
|
1945
1944
|
// Ignore this event if it was just us resetting the URL from a
|
|
1946
1945
|
// blocked POP navigation
|
|
1947
|
-
if (
|
|
1948
|
-
|
|
1946
|
+
if (unblockBlockerHistoryUpdate) {
|
|
1947
|
+
unblockBlockerHistoryUpdate();
|
|
1948
|
+
unblockBlockerHistoryUpdate = undefined;
|
|
1949
1949
|
return;
|
|
1950
1950
|
}
|
|
1951
1951
|
warning(blockerFunctions.size === 0 || delta != null, "You are trying to use a blocker on a POP navigation to a location " + "that was not created by @remix-run/router. This will fail silently in " + "production. This can happen if you are navigating outside the router " + "via `window.history.pushState`/`window.location.hash` instead of using " + "router navigation APIs. This can also happen if you are using " + "createHashRouter and the user manually changes the URL.");
|
|
@@ -1956,7 +1956,9 @@
|
|
|
1956
1956
|
});
|
|
1957
1957
|
if (blockerKey && delta != null) {
|
|
1958
1958
|
// Restore the URL to match the current UI, but don't update router state
|
|
1959
|
-
|
|
1959
|
+
let nextHistoryUpdatePromise = new Promise(resolve => {
|
|
1960
|
+
unblockBlockerHistoryUpdate = resolve;
|
|
1961
|
+
});
|
|
1960
1962
|
init.history.go(delta * -1);
|
|
1961
1963
|
|
|
1962
1964
|
// Put the blocker into a blocked state
|
|
@@ -1970,8 +1972,10 @@
|
|
|
1970
1972
|
reset: undefined,
|
|
1971
1973
|
location
|
|
1972
1974
|
});
|
|
1973
|
-
// Re-do the same POP navigation we just blocked
|
|
1974
|
-
|
|
1975
|
+
// Re-do the same POP navigation we just blocked, after the url
|
|
1976
|
+
// restoration is also complete. See:
|
|
1977
|
+
// https://github.com/remix-run/react-router/issues/11613
|
|
1978
|
+
nextHistoryUpdatePromise.then(() => init.history.go(delta));
|
|
1975
1979
|
},
|
|
1976
1980
|
reset() {
|
|
1977
1981
|
let blockers = new Map(state.blockers);
|
|
@@ -2291,7 +2295,9 @@
|
|
|
2291
2295
|
// navigation to the navigation.location but do not trigger an uninterrupted
|
|
2292
2296
|
// revalidation so that history correctly updates once the navigation completes
|
|
2293
2297
|
startNavigation(pendingAction || state.historyAction, state.navigation.location, {
|
|
2294
|
-
overrideNavigation: state.navigation
|
|
2298
|
+
overrideNavigation: state.navigation,
|
|
2299
|
+
// Proxy through any rending view transition
|
|
2300
|
+
enableViewTransition: pendingViewTransitionEnabled === true
|
|
2295
2301
|
});
|
|
2296
2302
|
}
|
|
2297
2303
|
|
|
@@ -2492,8 +2498,8 @@
|
|
|
2492
2498
|
})
|
|
2493
2499
|
};
|
|
2494
2500
|
} else {
|
|
2495
|
-
let results = await callDataStrategy("action", request, [actionMatch], matches);
|
|
2496
|
-
result = results[
|
|
2501
|
+
let results = await callDataStrategy("action", state, request, [actionMatch], matches, null);
|
|
2502
|
+
result = results[actionMatch.route.id];
|
|
2497
2503
|
if (request.signal.aborted) {
|
|
2498
2504
|
return {
|
|
2499
2505
|
shortCircuited: true
|
|
@@ -2511,7 +2517,7 @@
|
|
|
2511
2517
|
let location = normalizeRedirectLocation(result.response.headers.get("Location"), new URL(request.url), basename);
|
|
2512
2518
|
replace = location === state.location.pathname + state.location.search;
|
|
2513
2519
|
}
|
|
2514
|
-
await startRedirectNavigation(request, result, {
|
|
2520
|
+
await startRedirectNavigation(request, result, true, {
|
|
2515
2521
|
submission,
|
|
2516
2522
|
replace
|
|
2517
2523
|
});
|
|
@@ -2681,7 +2687,7 @@
|
|
|
2681
2687
|
let {
|
|
2682
2688
|
loaderResults,
|
|
2683
2689
|
fetcherResults
|
|
2684
|
-
} = await callLoadersAndMaybeResolveData(state
|
|
2690
|
+
} = await callLoadersAndMaybeResolveData(state, matches, matchesToLoad, revalidatingFetchers, request);
|
|
2685
2691
|
if (request.signal.aborted) {
|
|
2686
2692
|
return {
|
|
2687
2693
|
shortCircuited: true
|
|
@@ -2697,16 +2703,22 @@
|
|
|
2697
2703
|
revalidatingFetchers.forEach(rf => fetchControllers.delete(rf.key));
|
|
2698
2704
|
|
|
2699
2705
|
// If any loaders returned a redirect Response, start a new REPLACE navigation
|
|
2700
|
-
let redirect = findRedirect(
|
|
2706
|
+
let redirect = findRedirect(loaderResults);
|
|
2701
2707
|
if (redirect) {
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2708
|
+
await startRedirectNavigation(request, redirect.result, true, {
|
|
2709
|
+
replace
|
|
2710
|
+
});
|
|
2711
|
+
return {
|
|
2712
|
+
shortCircuited: true
|
|
2713
|
+
};
|
|
2714
|
+
}
|
|
2715
|
+
redirect = findRedirect(fetcherResults);
|
|
2716
|
+
if (redirect) {
|
|
2717
|
+
// If this redirect came from a fetcher make sure we mark it in
|
|
2718
|
+
// fetchRedirectIds so it doesn't get revalidated on the next set of
|
|
2719
|
+
// loader executions
|
|
2720
|
+
fetchRedirectIds.add(redirect.key);
|
|
2721
|
+
await startRedirectNavigation(request, redirect.result, true, {
|
|
2710
2722
|
replace
|
|
2711
2723
|
});
|
|
2712
2724
|
return {
|
|
@@ -2890,8 +2902,8 @@
|
|
|
2890
2902
|
// Call the action for the fetcher
|
|
2891
2903
|
fetchControllers.set(key, abortController);
|
|
2892
2904
|
let originatingLoadId = incrementingLoadId;
|
|
2893
|
-
let actionResults = await callDataStrategy("action", fetchRequest, [match], requestMatches);
|
|
2894
|
-
let actionResult = actionResults[
|
|
2905
|
+
let actionResults = await callDataStrategy("action", state, fetchRequest, [match], requestMatches, key);
|
|
2906
|
+
let actionResult = actionResults[match.route.id];
|
|
2895
2907
|
if (fetchRequest.signal.aborted) {
|
|
2896
2908
|
// We can delete this so long as we weren't aborted by our own fetcher
|
|
2897
2909
|
// re-submit which would have put _new_ controller is in fetchControllers
|
|
@@ -2923,7 +2935,7 @@
|
|
|
2923
2935
|
} else {
|
|
2924
2936
|
fetchRedirectIds.add(key);
|
|
2925
2937
|
updateFetcherState(key, getLoadingFetcher(submission));
|
|
2926
|
-
return startRedirectNavigation(fetchRequest, actionResult, {
|
|
2938
|
+
return startRedirectNavigation(fetchRequest, actionResult, false, {
|
|
2927
2939
|
fetcherSubmission: submission
|
|
2928
2940
|
});
|
|
2929
2941
|
}
|
|
@@ -2977,7 +2989,7 @@
|
|
|
2977
2989
|
let {
|
|
2978
2990
|
loaderResults,
|
|
2979
2991
|
fetcherResults
|
|
2980
|
-
} = await callLoadersAndMaybeResolveData(state
|
|
2992
|
+
} = await callLoadersAndMaybeResolveData(state, matches, matchesToLoad, revalidatingFetchers, revalidationRequest);
|
|
2981
2993
|
if (abortController.signal.aborted) {
|
|
2982
2994
|
return;
|
|
2983
2995
|
}
|
|
@@ -2985,23 +2997,24 @@
|
|
|
2985
2997
|
fetchReloadIds.delete(key);
|
|
2986
2998
|
fetchControllers.delete(key);
|
|
2987
2999
|
revalidatingFetchers.forEach(r => fetchControllers.delete(r.key));
|
|
2988
|
-
let redirect = findRedirect(
|
|
3000
|
+
let redirect = findRedirect(loaderResults);
|
|
2989
3001
|
if (redirect) {
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
3002
|
+
return startRedirectNavigation(revalidationRequest, redirect.result, false);
|
|
3003
|
+
}
|
|
3004
|
+
redirect = findRedirect(fetcherResults);
|
|
3005
|
+
if (redirect) {
|
|
3006
|
+
// If this redirect came from a fetcher make sure we mark it in
|
|
3007
|
+
// fetchRedirectIds so it doesn't get revalidated on the next set of
|
|
3008
|
+
// loader executions
|
|
3009
|
+
fetchRedirectIds.add(redirect.key);
|
|
3010
|
+
return startRedirectNavigation(revalidationRequest, redirect.result, false);
|
|
2998
3011
|
}
|
|
2999
3012
|
|
|
3000
3013
|
// Process and commit output from loaders
|
|
3001
3014
|
let {
|
|
3002
3015
|
loaderData,
|
|
3003
3016
|
errors
|
|
3004
|
-
} = processLoaderData(state,
|
|
3017
|
+
} = processLoaderData(state, matches, matchesToLoad, loaderResults, undefined, revalidatingFetchers, fetcherResults, activeDeferreds);
|
|
3005
3018
|
|
|
3006
3019
|
// Since we let revalidations complete even if the submitting fetcher was
|
|
3007
3020
|
// deleted, only put it back to idle if it hasn't been deleted
|
|
@@ -3072,8 +3085,8 @@
|
|
|
3072
3085
|
// Call the loader for this fetcher route match
|
|
3073
3086
|
fetchControllers.set(key, abortController);
|
|
3074
3087
|
let originatingLoadId = incrementingLoadId;
|
|
3075
|
-
let results = await callDataStrategy("loader", fetchRequest, [match], matches);
|
|
3076
|
-
let result = results[
|
|
3088
|
+
let results = await callDataStrategy("loader", state, fetchRequest, [match], matches, key);
|
|
3089
|
+
let result = results[match.route.id];
|
|
3077
3090
|
|
|
3078
3091
|
// Deferred isn't supported for fetcher loads, await everything and treat it
|
|
3079
3092
|
// as a normal load. resolveDeferredData will return undefined if this
|
|
@@ -3108,7 +3121,7 @@
|
|
|
3108
3121
|
return;
|
|
3109
3122
|
} else {
|
|
3110
3123
|
fetchRedirectIds.add(key);
|
|
3111
|
-
await startRedirectNavigation(fetchRequest, result);
|
|
3124
|
+
await startRedirectNavigation(fetchRequest, result, false);
|
|
3112
3125
|
return;
|
|
3113
3126
|
}
|
|
3114
3127
|
}
|
|
@@ -3143,7 +3156,7 @@
|
|
|
3143
3156
|
* actually touch history until we've processed redirects, so we just use
|
|
3144
3157
|
* the history action from the original navigation (PUSH or REPLACE).
|
|
3145
3158
|
*/
|
|
3146
|
-
async function startRedirectNavigation(request, redirect, _temp2) {
|
|
3159
|
+
async function startRedirectNavigation(request, redirect, isNavigation, _temp2) {
|
|
3147
3160
|
let {
|
|
3148
3161
|
submission,
|
|
3149
3162
|
fetcherSubmission,
|
|
@@ -3206,8 +3219,9 @@
|
|
|
3206
3219
|
submission: _extends({}, activeSubmission, {
|
|
3207
3220
|
formAction: location
|
|
3208
3221
|
}),
|
|
3209
|
-
// Preserve
|
|
3210
|
-
preventScrollReset: pendingPreventScrollReset
|
|
3222
|
+
// Preserve these flags across redirects
|
|
3223
|
+
preventScrollReset: pendingPreventScrollReset,
|
|
3224
|
+
enableViewTransition: isNavigation ? pendingViewTransitionEnabled : undefined
|
|
3211
3225
|
});
|
|
3212
3226
|
} else {
|
|
3213
3227
|
// If we have a navigation submission, we will preserve it through the
|
|
@@ -3217,51 +3231,71 @@
|
|
|
3217
3231
|
overrideNavigation,
|
|
3218
3232
|
// Send fetcher submissions through for shouldRevalidate
|
|
3219
3233
|
fetcherSubmission,
|
|
3220
|
-
// Preserve
|
|
3221
|
-
preventScrollReset: pendingPreventScrollReset
|
|
3234
|
+
// Preserve these flags across redirects
|
|
3235
|
+
preventScrollReset: pendingPreventScrollReset,
|
|
3236
|
+
enableViewTransition: isNavigation ? pendingViewTransitionEnabled : undefined
|
|
3222
3237
|
});
|
|
3223
3238
|
}
|
|
3224
3239
|
}
|
|
3225
3240
|
|
|
3226
3241
|
// Utility wrapper for calling dataStrategy client-side without having to
|
|
3227
3242
|
// pass around the manifest, mapRouteProperties, etc.
|
|
3228
|
-
async function callDataStrategy(type, request, matchesToLoad, matches) {
|
|
3243
|
+
async function callDataStrategy(type, state, request, matchesToLoad, matches, fetcherKey) {
|
|
3244
|
+
let results;
|
|
3245
|
+
let dataResults = {};
|
|
3229
3246
|
try {
|
|
3230
|
-
|
|
3231
|
-
return await Promise.all(results.map((result, i) => {
|
|
3232
|
-
if (isRedirectHandlerResult(result)) {
|
|
3233
|
-
let response = result.result;
|
|
3234
|
-
return {
|
|
3235
|
-
type: ResultType.redirect,
|
|
3236
|
-
response: normalizeRelativeRoutingRedirectResponse(response, request, matchesToLoad[i].route.id, matches, basename, future.v7_relativeSplatPath)
|
|
3237
|
-
};
|
|
3238
|
-
}
|
|
3239
|
-
return convertHandlerResultToDataResult(result);
|
|
3240
|
-
}));
|
|
3247
|
+
results = await callDataStrategyImpl(dataStrategyImpl, type, state, request, matchesToLoad, matches, fetcherKey, manifest, mapRouteProperties);
|
|
3241
3248
|
} catch (e) {
|
|
3242
3249
|
// If the outer dataStrategy method throws, just return the error for all
|
|
3243
3250
|
// matches - and it'll naturally bubble to the root
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3251
|
+
matchesToLoad.forEach(m => {
|
|
3252
|
+
dataResults[m.route.id] = {
|
|
3253
|
+
type: ResultType.error,
|
|
3254
|
+
error: e
|
|
3255
|
+
};
|
|
3256
|
+
});
|
|
3257
|
+
return dataResults;
|
|
3258
|
+
}
|
|
3259
|
+
for (let [routeId, result] of Object.entries(results)) {
|
|
3260
|
+
if (isRedirectDataStrategyResultResult(result)) {
|
|
3261
|
+
let response = result.result;
|
|
3262
|
+
dataResults[routeId] = {
|
|
3263
|
+
type: ResultType.redirect,
|
|
3264
|
+
response: normalizeRelativeRoutingRedirectResponse(response, request, routeId, matches, basename, future.v7_relativeSplatPath)
|
|
3265
|
+
};
|
|
3266
|
+
} else {
|
|
3267
|
+
dataResults[routeId] = await convertDataStrategyResultToDataResult(result);
|
|
3268
|
+
}
|
|
3248
3269
|
}
|
|
3270
|
+
return dataResults;
|
|
3249
3271
|
}
|
|
3250
|
-
async function callLoadersAndMaybeResolveData(
|
|
3251
|
-
let
|
|
3272
|
+
async function callLoadersAndMaybeResolveData(state, matches, matchesToLoad, fetchersToLoad, request) {
|
|
3273
|
+
let currentMatches = state.matches;
|
|
3274
|
+
|
|
3275
|
+
// Kick off loaders and fetchers in parallel
|
|
3276
|
+
let loaderResultsPromise = callDataStrategy("loader", state, request, matchesToLoad, matches, null);
|
|
3277
|
+
let fetcherResultsPromise = Promise.all(fetchersToLoad.map(async f => {
|
|
3252
3278
|
if (f.matches && f.match && f.controller) {
|
|
3253
|
-
let
|
|
3254
|
-
|
|
3279
|
+
let results = await callDataStrategy("loader", state, createClientSideRequest(init.history, f.path, f.controller.signal), [f.match], f.matches, f.key);
|
|
3280
|
+
let result = results[f.match.route.id];
|
|
3281
|
+
// Fetcher results are keyed by fetcher key from here on out, not routeId
|
|
3282
|
+
return {
|
|
3283
|
+
[f.key]: result
|
|
3284
|
+
};
|
|
3255
3285
|
} else {
|
|
3256
3286
|
return Promise.resolve({
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3287
|
+
[f.key]: {
|
|
3288
|
+
type: ResultType.error,
|
|
3289
|
+
error: getInternalRouterError(404, {
|
|
3290
|
+
pathname: f.path
|
|
3291
|
+
})
|
|
3292
|
+
}
|
|
3261
3293
|
});
|
|
3262
3294
|
}
|
|
3263
|
-
})
|
|
3264
|
-
|
|
3295
|
+
}));
|
|
3296
|
+
let loaderResults = await loaderResultsPromise;
|
|
3297
|
+
let fetcherResults = (await fetcherResultsPromise).reduce((acc, r) => Object.assign(acc, r), {});
|
|
3298
|
+
await Promise.all([resolveNavigationDeferredResults(matches, loaderResults, request.signal, currentMatches, state.loaderData), resolveFetcherDeferredResults(matches, fetcherResults, fetchersToLoad)]);
|
|
3265
3299
|
return {
|
|
3266
3300
|
loaderResults,
|
|
3267
3301
|
fetcherResults
|
|
@@ -3928,9 +3962,9 @@
|
|
|
3928
3962
|
});
|
|
3929
3963
|
} catch (e) {
|
|
3930
3964
|
// If the user threw/returned a Response in callLoaderOrAction for a
|
|
3931
|
-
// `queryRoute` call, we throw the `
|
|
3965
|
+
// `queryRoute` call, we throw the `DataStrategyResult` to bail out early
|
|
3932
3966
|
// and then return or throw the raw Response here accordingly
|
|
3933
|
-
if (
|
|
3967
|
+
if (isDataStrategyResult(e) && isResponse(e.result)) {
|
|
3934
3968
|
if (e.type === ResultType.error) {
|
|
3935
3969
|
throw e.result;
|
|
3936
3970
|
}
|
|
@@ -3961,7 +3995,7 @@
|
|
|
3961
3995
|
};
|
|
3962
3996
|
} else {
|
|
3963
3997
|
let results = await callDataStrategy("action", request, [actionMatch], matches, isRouteRequest, requestContext, unstable_dataStrategy);
|
|
3964
|
-
result = results[
|
|
3998
|
+
result = results[actionMatch.route.id];
|
|
3965
3999
|
if (request.signal.aborted) {
|
|
3966
4000
|
throwStaticHandlerAbortedError(request, isRouteRequest, future);
|
|
3967
4001
|
}
|
|
@@ -4083,7 +4117,7 @@
|
|
|
4083
4117
|
|
|
4084
4118
|
// Process and commit output from loaders
|
|
4085
4119
|
let activeDeferreds = new Map();
|
|
4086
|
-
let context = processRouteLoaderData(matches,
|
|
4120
|
+
let context = processRouteLoaderData(matches, results, pendingActionResult, activeDeferreds, skipLoaderErrorBubbling);
|
|
4087
4121
|
|
|
4088
4122
|
// Add a null for any non-loader matches for proper revalidation on the client
|
|
4089
4123
|
let executedLoaders = new Set(matchesToLoad.map(match => match.route.id));
|
|
@@ -4101,20 +4135,26 @@
|
|
|
4101
4135
|
// Utility wrapper for calling dataStrategy server-side without having to
|
|
4102
4136
|
// pass around the manifest, mapRouteProperties, etc.
|
|
4103
4137
|
async function callDataStrategy(type, request, matchesToLoad, matches, isRouteRequest, requestContext, unstable_dataStrategy) {
|
|
4104
|
-
let results = await callDataStrategyImpl(unstable_dataStrategy || defaultDataStrategy, type, request, matchesToLoad, matches, manifest, mapRouteProperties, requestContext);
|
|
4105
|
-
|
|
4106
|
-
|
|
4138
|
+
let results = await callDataStrategyImpl(unstable_dataStrategy || defaultDataStrategy, type, null, request, matchesToLoad, matches, null, manifest, mapRouteProperties, requestContext);
|
|
4139
|
+
let dataResults = {};
|
|
4140
|
+
await Promise.all(matches.map(async match => {
|
|
4141
|
+
if (!(match.route.id in results)) {
|
|
4142
|
+
return;
|
|
4143
|
+
}
|
|
4144
|
+
let result = results[match.route.id];
|
|
4145
|
+
if (isRedirectDataStrategyResultResult(result)) {
|
|
4107
4146
|
let response = result.result;
|
|
4108
4147
|
// Throw redirects and let the server handle them with an HTTP redirect
|
|
4109
|
-
throw normalizeRelativeRoutingRedirectResponse(response, request,
|
|
4148
|
+
throw normalizeRelativeRoutingRedirectResponse(response, request, match.route.id, matches, basename, future.v7_relativeSplatPath);
|
|
4110
4149
|
}
|
|
4111
4150
|
if (isResponse(result.result) && isRouteRequest) {
|
|
4112
4151
|
// For SSR single-route requests, we want to hand Responses back
|
|
4113
4152
|
// directly without unwrapping
|
|
4114
4153
|
throw result;
|
|
4115
4154
|
}
|
|
4116
|
-
|
|
4155
|
+
dataResults[match.route.id] = await convertDataStrategyResultToDataResult(result);
|
|
4117
4156
|
}));
|
|
4157
|
+
return dataResults;
|
|
4118
4158
|
}
|
|
4119
4159
|
return {
|
|
4120
4160
|
dataRoutes,
|
|
@@ -4603,56 +4643,70 @@
|
|
|
4603
4643
|
}
|
|
4604
4644
|
|
|
4605
4645
|
// Default implementation of `dataStrategy` which fetches all loaders in parallel
|
|
4606
|
-
function defaultDataStrategy(
|
|
4607
|
-
|
|
4646
|
+
async function defaultDataStrategy(_ref6) {
|
|
4647
|
+
let {
|
|
4648
|
+
matches
|
|
4649
|
+
} = _ref6;
|
|
4650
|
+
let matchesToLoad = matches.filter(m => m.shouldLoad);
|
|
4651
|
+
let results = await Promise.all(matchesToLoad.map(m => m.resolve()));
|
|
4652
|
+
return results.reduce((acc, result, i) => Object.assign(acc, {
|
|
4653
|
+
[matchesToLoad[i].route.id]: result
|
|
4654
|
+
}), {});
|
|
4608
4655
|
}
|
|
4609
|
-
async function callDataStrategyImpl(dataStrategyImpl, type, request, matchesToLoad, matches, manifest, mapRouteProperties, requestContext) {
|
|
4610
|
-
let
|
|
4611
|
-
let
|
|
4656
|
+
async function callDataStrategyImpl(dataStrategyImpl, type, state, request, matchesToLoad, matches, fetcherKey, manifest, mapRouteProperties, requestContext) {
|
|
4657
|
+
let loadRouteDefinitionsPromises = matches.map(m => m.route.lazy ? loadLazyRouteModule(m.route, mapRouteProperties, manifest) : undefined);
|
|
4658
|
+
let dsMatches = matches.map((match, i) => {
|
|
4659
|
+
let loadRoutePromise = loadRouteDefinitionsPromises[i];
|
|
4660
|
+
let shouldLoad = matchesToLoad.some(m => m.route.id === match.route.id);
|
|
4661
|
+
// `resolve` encapsulates route.lazy(), executing the loader/action,
|
|
4662
|
+
// and mapping return values/thrown errors to a `DataStrategyResult`. Users
|
|
4663
|
+
// can pass a callback to take fine-grained control over the execution
|
|
4664
|
+
// of the loader/action
|
|
4665
|
+
let resolve = async handlerOverride => {
|
|
4666
|
+
if (handlerOverride && request.method === "GET" && (match.route.lazy || match.route.loader)) {
|
|
4667
|
+
shouldLoad = true;
|
|
4668
|
+
}
|
|
4669
|
+
return shouldLoad ? callLoaderOrAction(type, request, match, loadRoutePromise, handlerOverride, requestContext) : Promise.resolve({
|
|
4670
|
+
type: ResultType.data,
|
|
4671
|
+
result: undefined
|
|
4672
|
+
});
|
|
4673
|
+
};
|
|
4674
|
+
return _extends({}, match, {
|
|
4675
|
+
shouldLoad,
|
|
4676
|
+
resolve
|
|
4677
|
+
});
|
|
4678
|
+
});
|
|
4612
4679
|
|
|
4613
4680
|
// Send all matches here to allow for a middleware-type implementation.
|
|
4614
4681
|
// handler will be a no-op for unneeded routes and we filter those results
|
|
4615
4682
|
// back out below.
|
|
4616
4683
|
let results = await dataStrategyImpl({
|
|
4617
|
-
matches:
|
|
4618
|
-
let shouldLoad = routeIdsToLoad.has(match.route.id);
|
|
4619
|
-
// `resolve` encapsulates the route.lazy, executing the
|
|
4620
|
-
// loader/action, and mapping return values/thrown errors to a
|
|
4621
|
-
// HandlerResult. Users can pass a callback to take fine-grained control
|
|
4622
|
-
// over the execution of the loader/action
|
|
4623
|
-
let resolve = handlerOverride => {
|
|
4624
|
-
loadedMatches.add(match.route.id);
|
|
4625
|
-
return shouldLoad ? callLoaderOrAction(type, request, match, manifest, mapRouteProperties, handlerOverride, requestContext) : Promise.resolve({
|
|
4626
|
-
type: ResultType.data,
|
|
4627
|
-
result: undefined
|
|
4628
|
-
});
|
|
4629
|
-
};
|
|
4630
|
-
return _extends({}, match, {
|
|
4631
|
-
shouldLoad,
|
|
4632
|
-
resolve
|
|
4633
|
-
});
|
|
4634
|
-
}),
|
|
4684
|
+
matches: dsMatches,
|
|
4635
4685
|
request,
|
|
4636
4686
|
params: matches[0].params,
|
|
4687
|
+
fetcherKey,
|
|
4637
4688
|
context: requestContext
|
|
4638
4689
|
});
|
|
4639
4690
|
|
|
4640
|
-
//
|
|
4641
|
-
//
|
|
4642
|
-
|
|
4643
|
-
|
|
4644
|
-
|
|
4645
|
-
|
|
4691
|
+
// Wait for all routes to load here but 'swallow the error since we want
|
|
4692
|
+
// it to bubble up from the `await loadRoutePromise` in `callLoaderOrAction` -
|
|
4693
|
+
// called from `match.resolve()`
|
|
4694
|
+
try {
|
|
4695
|
+
await Promise.all(loadRouteDefinitionsPromises);
|
|
4696
|
+
} catch (e) {
|
|
4697
|
+
// No-op
|
|
4698
|
+
}
|
|
4699
|
+
return results;
|
|
4646
4700
|
}
|
|
4647
4701
|
|
|
4648
4702
|
// Default logic for calling a loader/action is the user has no specified a dataStrategy
|
|
4649
|
-
async function callLoaderOrAction(type, request, match,
|
|
4703
|
+
async function callLoaderOrAction(type, request, match, loadRoutePromise, handlerOverride, staticContext) {
|
|
4650
4704
|
let result;
|
|
4651
4705
|
let onReject;
|
|
4652
4706
|
let runHandler = handler => {
|
|
4653
4707
|
// Setup a promise we can race against so that abort signals short circuit
|
|
4654
4708
|
let reject;
|
|
4655
|
-
// This will never resolve so safe to type it as Promise<
|
|
4709
|
+
// This will never resolve so safe to type it as Promise<DataStrategyResult> to
|
|
4656
4710
|
// satisfy the function return value
|
|
4657
4711
|
let abortPromise = new Promise((_, r) => reject = r);
|
|
4658
4712
|
onReject = () => reject();
|
|
@@ -4667,30 +4721,27 @@
|
|
|
4667
4721
|
context: staticContext
|
|
4668
4722
|
}, ...(ctx !== undefined ? [ctx] : []));
|
|
4669
4723
|
};
|
|
4670
|
-
let handlerPromise
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
}
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
result: e
|
|
4685
|
-
};
|
|
4686
|
-
}
|
|
4687
|
-
})();
|
|
4688
|
-
}
|
|
4724
|
+
let handlerPromise = (async () => {
|
|
4725
|
+
try {
|
|
4726
|
+
let val = await (handlerOverride ? handlerOverride(ctx => actualHandler(ctx)) : actualHandler());
|
|
4727
|
+
return {
|
|
4728
|
+
type: "data",
|
|
4729
|
+
result: val
|
|
4730
|
+
};
|
|
4731
|
+
} catch (e) {
|
|
4732
|
+
return {
|
|
4733
|
+
type: "error",
|
|
4734
|
+
result: e
|
|
4735
|
+
};
|
|
4736
|
+
}
|
|
4737
|
+
})();
|
|
4689
4738
|
return Promise.race([handlerPromise, abortPromise]);
|
|
4690
4739
|
};
|
|
4691
4740
|
try {
|
|
4692
4741
|
let handler = match.route[type];
|
|
4693
|
-
|
|
4742
|
+
|
|
4743
|
+
// If we have a route.lazy promise, await that first
|
|
4744
|
+
if (loadRoutePromise) {
|
|
4694
4745
|
if (handler) {
|
|
4695
4746
|
// Run statically defined handler in parallel with lazy()
|
|
4696
4747
|
let handlerError;
|
|
@@ -4700,14 +4751,14 @@
|
|
|
4700
4751
|
// route has a boundary that can handle the error
|
|
4701
4752
|
runHandler(handler).catch(e => {
|
|
4702
4753
|
handlerError = e;
|
|
4703
|
-
}),
|
|
4754
|
+
}), loadRoutePromise]);
|
|
4704
4755
|
if (handlerError !== undefined) {
|
|
4705
4756
|
throw handlerError;
|
|
4706
4757
|
}
|
|
4707
4758
|
result = value;
|
|
4708
4759
|
} else {
|
|
4709
4760
|
// Load lazy route module, then run any returned handler
|
|
4710
|
-
await
|
|
4761
|
+
await loadRoutePromise;
|
|
4711
4762
|
handler = match.route[type];
|
|
4712
4763
|
if (handler) {
|
|
4713
4764
|
// Handler still runs even if we got interrupted to maintain consistency
|
|
@@ -4743,7 +4794,7 @@
|
|
|
4743
4794
|
invariant(result.result !== undefined, "You defined " + (type === "action" ? "an action" : "a loader") + " for route " + ("\"" + match.route.id + "\" but didn't return anything from your `" + type + "` ") + "function. Please return a value or `null`.");
|
|
4744
4795
|
} catch (e) {
|
|
4745
4796
|
// We should already be catching and converting normal handler executions to
|
|
4746
|
-
//
|
|
4797
|
+
// DataStrategyResults and returning them, so anything that throws here is an
|
|
4747
4798
|
// unexpected error we still need to wrap
|
|
4748
4799
|
return {
|
|
4749
4800
|
type: ResultType.error,
|
|
@@ -4756,11 +4807,11 @@
|
|
|
4756
4807
|
}
|
|
4757
4808
|
return result;
|
|
4758
4809
|
}
|
|
4759
|
-
async function
|
|
4810
|
+
async function convertDataStrategyResultToDataResult(dataStrategyResult) {
|
|
4760
4811
|
let {
|
|
4761
4812
|
result,
|
|
4762
4813
|
type
|
|
4763
|
-
} =
|
|
4814
|
+
} = dataStrategyResult;
|
|
4764
4815
|
if (isResponse(result)) {
|
|
4765
4816
|
let data;
|
|
4766
4817
|
try {
|
|
@@ -4916,7 +4967,7 @@
|
|
|
4916
4967
|
}
|
|
4917
4968
|
return formData;
|
|
4918
4969
|
}
|
|
4919
|
-
function processRouteLoaderData(matches,
|
|
4970
|
+
function processRouteLoaderData(matches, results, pendingActionResult, activeDeferreds, skipLoaderErrorBubbling) {
|
|
4920
4971
|
// Fill in loaderData/errors from our loaders
|
|
4921
4972
|
let loaderData = {};
|
|
4922
4973
|
let errors = null;
|
|
@@ -4926,8 +4977,12 @@
|
|
|
4926
4977
|
let pendingError = pendingActionResult && isErrorResult(pendingActionResult[1]) ? pendingActionResult[1].error : undefined;
|
|
4927
4978
|
|
|
4928
4979
|
// Process loader results into state.loaderData/state.errors
|
|
4929
|
-
|
|
4930
|
-
|
|
4980
|
+
matches.forEach(match => {
|
|
4981
|
+
if (!(match.route.id in results)) {
|
|
4982
|
+
return;
|
|
4983
|
+
}
|
|
4984
|
+
let id = match.route.id;
|
|
4985
|
+
let result = results[id];
|
|
4931
4986
|
invariant(!isRedirectResult(result), "Cannot handle redirect results in processLoaderData");
|
|
4932
4987
|
if (isErrorResult(result)) {
|
|
4933
4988
|
let error = result.error;
|
|
@@ -5009,23 +5064,23 @@
|
|
|
5009
5064
|
let {
|
|
5010
5065
|
loaderData,
|
|
5011
5066
|
errors
|
|
5012
|
-
} = processRouteLoaderData(matches,
|
|
5067
|
+
} = processRouteLoaderData(matches, results, pendingActionResult, activeDeferreds, false // This method is only called client side so we always want to bubble
|
|
5013
5068
|
);
|
|
5014
5069
|
|
|
5015
5070
|
// Process results from our revalidating fetchers
|
|
5016
|
-
|
|
5071
|
+
revalidatingFetchers.forEach(rf => {
|
|
5017
5072
|
let {
|
|
5018
5073
|
key,
|
|
5019
5074
|
match,
|
|
5020
5075
|
controller
|
|
5021
|
-
} =
|
|
5022
|
-
|
|
5023
|
-
|
|
5076
|
+
} = rf;
|
|
5077
|
+
let result = fetcherResults[key];
|
|
5078
|
+
invariant(result, "Did not find corresponding fetcher result");
|
|
5024
5079
|
|
|
5025
5080
|
// Process fetcher non-redirect errors
|
|
5026
5081
|
if (controller && controller.signal.aborted) {
|
|
5027
5082
|
// Nothing to do for aborted fetchers
|
|
5028
|
-
|
|
5083
|
+
return;
|
|
5029
5084
|
} else if (isErrorResult(result)) {
|
|
5030
5085
|
let boundaryMatch = findNearestBoundary(state.matches, match == null ? void 0 : match.route.id);
|
|
5031
5086
|
if (!(errors && errors[boundaryMatch.route.id])) {
|
|
@@ -5046,7 +5101,7 @@
|
|
|
5046
5101
|
let doneFetcher = getDoneFetcher(result.data);
|
|
5047
5102
|
state.fetchers.set(key, doneFetcher);
|
|
5048
5103
|
}
|
|
5049
|
-
}
|
|
5104
|
+
});
|
|
5050
5105
|
return {
|
|
5051
5106
|
loaderData,
|
|
5052
5107
|
errors
|
|
@@ -5148,12 +5203,13 @@
|
|
|
5148
5203
|
|
|
5149
5204
|
// Find any returned redirect errors, starting from the lowest match
|
|
5150
5205
|
function findRedirect(results) {
|
|
5151
|
-
|
|
5152
|
-
|
|
5206
|
+
let entries = Object.entries(results);
|
|
5207
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
5208
|
+
let [key, result] = entries[i];
|
|
5153
5209
|
if (isRedirectResult(result)) {
|
|
5154
5210
|
return {
|
|
5155
|
-
|
|
5156
|
-
|
|
5211
|
+
key,
|
|
5212
|
+
result
|
|
5157
5213
|
};
|
|
5158
5214
|
}
|
|
5159
5215
|
}
|
|
@@ -5186,10 +5242,10 @@
|
|
|
5186
5242
|
function isPromise(val) {
|
|
5187
5243
|
return typeof val === "object" && val != null && "then" in val;
|
|
5188
5244
|
}
|
|
5189
|
-
function
|
|
5245
|
+
function isDataStrategyResult(result) {
|
|
5190
5246
|
return result != null && typeof result === "object" && "type" in result && "result" in result && (result.type === ResultType.data || result.type === ResultType.error);
|
|
5191
5247
|
}
|
|
5192
|
-
function
|
|
5248
|
+
function isRedirectDataStrategyResultResult(result) {
|
|
5193
5249
|
return isResponse(result.result) && redirectStatusCodes.has(result.result.status);
|
|
5194
5250
|
}
|
|
5195
5251
|
function isDeferredResult(result) {
|
|
@@ -5225,10 +5281,11 @@
|
|
|
5225
5281
|
function isMutationMethod(method) {
|
|
5226
5282
|
return validMutationMethods.has(method.toLowerCase());
|
|
5227
5283
|
}
|
|
5228
|
-
async function
|
|
5229
|
-
|
|
5230
|
-
|
|
5231
|
-
let
|
|
5284
|
+
async function resolveNavigationDeferredResults(matches, results, signal, currentMatches, currentLoaderData) {
|
|
5285
|
+
let entries = Object.entries(results);
|
|
5286
|
+
for (let index = 0; index < entries.length; index++) {
|
|
5287
|
+
let [routeId, result] = entries[index];
|
|
5288
|
+
let match = matches.find(m => (m == null ? void 0 : m.route.id) === routeId);
|
|
5232
5289
|
// If we don't have a match, then we can have a deferred result to do
|
|
5233
5290
|
// anything with. This is for revalidating fetchers where the route was
|
|
5234
5291
|
// removed during HMR
|
|
@@ -5237,15 +5294,41 @@
|
|
|
5237
5294
|
}
|
|
5238
5295
|
let currentMatch = currentMatches.find(m => m.route.id === match.route.id);
|
|
5239
5296
|
let isRevalidatingLoader = currentMatch != null && !isNewRouteInstance(currentMatch, match) && (currentLoaderData && currentLoaderData[match.route.id]) !== undefined;
|
|
5240
|
-
if (isDeferredResult(result) &&
|
|
5297
|
+
if (isDeferredResult(result) && isRevalidatingLoader) {
|
|
5298
|
+
// Note: we do not have to touch activeDeferreds here since we race them
|
|
5299
|
+
// against the signal in resolveDeferredData and they'll get aborted
|
|
5300
|
+
// there if needed
|
|
5301
|
+
await resolveDeferredData(result, signal, false).then(result => {
|
|
5302
|
+
if (result) {
|
|
5303
|
+
results[routeId] = result;
|
|
5304
|
+
}
|
|
5305
|
+
});
|
|
5306
|
+
}
|
|
5307
|
+
}
|
|
5308
|
+
}
|
|
5309
|
+
async function resolveFetcherDeferredResults(matches, results, revalidatingFetchers) {
|
|
5310
|
+
for (let index = 0; index < revalidatingFetchers.length; index++) {
|
|
5311
|
+
let {
|
|
5312
|
+
key,
|
|
5313
|
+
routeId,
|
|
5314
|
+
controller
|
|
5315
|
+
} = revalidatingFetchers[index];
|
|
5316
|
+
let result = results[key];
|
|
5317
|
+
let match = matches.find(m => (m == null ? void 0 : m.route.id) === routeId);
|
|
5318
|
+
// If we don't have a match, then we can have a deferred result to do
|
|
5319
|
+
// anything with. This is for revalidating fetchers where the route was
|
|
5320
|
+
// removed during HMR
|
|
5321
|
+
if (!match) {
|
|
5322
|
+
continue;
|
|
5323
|
+
}
|
|
5324
|
+
if (isDeferredResult(result)) {
|
|
5241
5325
|
// Note: we do not have to touch activeDeferreds here since we race them
|
|
5242
5326
|
// against the signal in resolveDeferredData and they'll get aborted
|
|
5243
5327
|
// there if needed
|
|
5244
|
-
|
|
5245
|
-
|
|
5246
|
-
await resolveDeferredData(result, signal, isFetcher).then(result => {
|
|
5328
|
+
invariant(controller, "Expected an AbortController for revalidating fetcher deferred result");
|
|
5329
|
+
await resolveDeferredData(result, controller.signal, true).then(result => {
|
|
5247
5330
|
if (result) {
|
|
5248
|
-
results[
|
|
5331
|
+
results[key] = result;
|
|
5249
5332
|
}
|
|
5250
5333
|
});
|
|
5251
5334
|
}
|