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