@remix-run/router 0.0.0-experimental-432fcb2e → 0.0.0-experimental-c7dd3d3a
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 +7 -0
- package/dist/index.d.ts +1 -1
- package/dist/router.cjs.js +77 -51
- package/dist/router.cjs.js.map +1 -1
- package/dist/router.d.ts +1 -0
- package/dist/router.js +76 -50
- package/dist/router.js.map +1 -1
- package/dist/router.umd.js +77 -51
- 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 +2 -1
- package/index.ts +3 -3
- package/package.json +1 -1
- package/router.ts +112 -55
- package/utils.ts +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# `@remix-run/router`
|
|
2
2
|
|
|
3
|
+
## 1.15.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Fix a `future.v7_partialHydration` bug that would re-run loaders below the boundary on hydration if SSR loader errors bubbled to a parent boundary ([#11324](https://github.com/remix-run/react-router/pull/11324))
|
|
8
|
+
- Fix a `future.v7_partialHydration` bug that would consider the router uninitialized if a route did not have a loader ([#11325](https://github.com/remix-run/react-router/pull/11325))
|
|
9
|
+
|
|
3
10
|
## 1.15.2
|
|
4
11
|
|
|
5
12
|
### Patch Changes
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type { ActionFunction, ActionFunctionArgs, AgnosticDataIndexRouteObject, AgnosticDataNonIndexRouteObject, AgnosticDataRouteMatch, AgnosticDataRouteObject, AgnosticIndexRouteObject, AgnosticNonIndexRouteObject, AgnosticRouteMatch, AgnosticRouteObject, DataStrategyFunction, DataStrategyFunctionArgs, DataStrategyMatch, ErrorResponse, FormEncType, FormMethod, HandlerResult as unstable_HandlerResult, HTMLFormMethod, JsonFunction, LazyRouteFunction, LoaderFunction, LoaderFunctionArgs, ParamParseKey, Params, PathMatch, PathParam, PathPattern, RedirectFunction, ShouldRevalidateFunction, ShouldRevalidateFunctionArgs, TrackedPromise, UIMatch, V7_FormMethod, } from "./utils";
|
|
1
|
+
export type { ActionFunction, ActionFunctionArgs, AgnosticDataIndexRouteObject, AgnosticDataNonIndexRouteObject, AgnosticDataRouteMatch, AgnosticDataRouteObject, AgnosticIndexRouteObject, AgnosticNonIndexRouteObject, AgnosticRouteMatch, AgnosticRouteObject, DataStrategyFunction as unstable_DataStrategyFunction, DataStrategyFunctionArgs as unstable_DataStrategyFunctionArgs, DataStrategyMatch as unstable_DataStrategyMatch, ErrorResponse, FormEncType, FormMethod, HandlerResult as unstable_HandlerResult, HTMLFormMethod, JsonFunction, LazyRouteFunction, LoaderFunction, LoaderFunctionArgs, ParamParseKey, Params, PathMatch, PathParam, PathPattern, RedirectFunction, ShouldRevalidateFunction, ShouldRevalidateFunctionArgs, TrackedPromise, UIMatch, V7_FormMethod, } from "./utils";
|
|
2
2
|
export { AbortedDeferredError, defer, generatePath, getToPathname, isRouteErrorResponse, joinPaths, json, matchPath, matchRoutes, normalizePathname, redirect, redirectDocument, resolvePath, resolveTo, stripBasename, } from "./utils";
|
|
3
3
|
export type { BrowserHistory, BrowserHistoryOptions, HashHistory, HashHistoryOptions, History, InitialEntry, Location, MemoryHistory, MemoryHistoryOptions, Path, To, } from "./history";
|
|
4
4
|
export { Action, createBrowserHistory, createHashHistory, createMemoryHistory, createPath, parsePath, } from "./history";
|
package/dist/router.cjs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @remix-run/router v0.0.0-experimental-
|
|
2
|
+
* @remix-run/router v0.0.0-experimental-c7dd3d3a
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -1676,7 +1676,7 @@ function createRouter(init) {
|
|
|
1676
1676
|
v7_partialHydration: false,
|
|
1677
1677
|
v7_prependBasename: false,
|
|
1678
1678
|
v7_relativeSplatPath: false,
|
|
1679
|
-
unstable_skipActionErrorRevalidation:
|
|
1679
|
+
unstable_skipActionErrorRevalidation: false
|
|
1680
1680
|
}, init.future);
|
|
1681
1681
|
// Cleanup function for history
|
|
1682
1682
|
let unlistenHistory = null;
|
|
@@ -1728,7 +1728,26 @@ function createRouter(init) {
|
|
|
1728
1728
|
// were marked for explicit hydration
|
|
1729
1729
|
let loaderData = init.hydrationData ? init.hydrationData.loaderData : null;
|
|
1730
1730
|
let errors = init.hydrationData ? init.hydrationData.errors : null;
|
|
1731
|
-
|
|
1731
|
+
let isRouteInitialized = m => {
|
|
1732
|
+
// No loader, nothing to initialize
|
|
1733
|
+
if (!m.route.loader) {
|
|
1734
|
+
return true;
|
|
1735
|
+
}
|
|
1736
|
+
// Explicitly opting-in to running on hydration
|
|
1737
|
+
if (typeof m.route.loader === "function" && m.route.loader.hydrate === true) {
|
|
1738
|
+
return false;
|
|
1739
|
+
}
|
|
1740
|
+
// Otherwise, initialized if hydrated with data or an error
|
|
1741
|
+
return loaderData && loaderData[m.route.id] !== undefined || errors && errors[m.route.id] !== undefined;
|
|
1742
|
+
};
|
|
1743
|
+
|
|
1744
|
+
// If errors exist, don't consider routes below the boundary
|
|
1745
|
+
if (errors) {
|
|
1746
|
+
let idx = initialMatches.findIndex(m => errors[m.route.id] !== undefined);
|
|
1747
|
+
initialized = initialMatches.slice(0, idx + 1).every(isRouteInitialized);
|
|
1748
|
+
} else {
|
|
1749
|
+
initialized = initialMatches.every(isRouteInitialized);
|
|
1750
|
+
}
|
|
1732
1751
|
} else {
|
|
1733
1752
|
// Without partial hydration - we're initialized if we were provided any
|
|
1734
1753
|
// hydrationData - which is expected to be complete
|
|
@@ -2352,7 +2371,8 @@ function createRouter(init) {
|
|
|
2352
2371
|
// If the user didn't explicity indicate replace behavior, replace if
|
|
2353
2372
|
// we redirected to the exact same location we're currently at to avoid
|
|
2354
2373
|
// double back-buttons
|
|
2355
|
-
|
|
2374
|
+
let location = normalizeRedirectLocation(result.response.headers.get("Location"), new URL(request.url), basename);
|
|
2375
|
+
replace = location === state.location.pathname + state.location.search;
|
|
2356
2376
|
}
|
|
2357
2377
|
await startRedirectNavigation(request, result, {
|
|
2358
2378
|
submission,
|
|
@@ -2870,22 +2890,10 @@ function createRouter(init) {
|
|
|
2870
2890
|
}
|
|
2871
2891
|
let location = redirect.response.headers.get("Location");
|
|
2872
2892
|
invariant(location, "Expected a Location header on the redirect Response");
|
|
2893
|
+
location = normalizeRedirectLocation(location, new URL(request.url), basename);
|
|
2873
2894
|
let redirectLocation = createLocation(state.location, location, {
|
|
2874
2895
|
_isRedirect: true
|
|
2875
2896
|
});
|
|
2876
|
-
if (ABSOLUTE_URL_REGEX.test(location)) {
|
|
2877
|
-
// Strip off the protocol+origin for same-origin + same-basename absolute redirects
|
|
2878
|
-
let normalizedLocation = location;
|
|
2879
|
-
let currentUrl = new URL(request.url);
|
|
2880
|
-
let url = normalizedLocation.startsWith("//") ? new URL(currentUrl.protocol + normalizedLocation) : new URL(normalizedLocation);
|
|
2881
|
-
let isSameBasename = stripBasename(url.pathname, basename) != null;
|
|
2882
|
-
if (url.origin === currentUrl.origin && isSameBasename) {
|
|
2883
|
-
normalizedLocation = url.pathname + url.search + url.hash;
|
|
2884
|
-
redirectLocation = createLocation(state.location, normalizedLocation, {
|
|
2885
|
-
_isRedirect: true
|
|
2886
|
-
});
|
|
2887
|
-
}
|
|
2888
|
-
}
|
|
2889
2897
|
if (isBrowser) {
|
|
2890
2898
|
let isDocumentReload = false;
|
|
2891
2899
|
if (redirect.response.headers.has("X-Remix-Reload-Document")) {
|
|
@@ -2958,9 +2966,10 @@ function createRouter(init) {
|
|
|
2958
2966
|
let results = await callDataStrategyImpl(dataStrategyImpl, type, request, matchesToLoad, matches, manifest, mapRouteProperties);
|
|
2959
2967
|
return await Promise.all(results.map((result, i) => {
|
|
2960
2968
|
if (isRedirectHandlerResult(result)) {
|
|
2969
|
+
let response = result.result;
|
|
2961
2970
|
return {
|
|
2962
2971
|
type: ResultType.redirect,
|
|
2963
|
-
response: normalizeRelativeRoutingRedirectResponse(
|
|
2972
|
+
response: normalizeRelativeRoutingRedirectResponse(response, request, matchesToLoad[i].route.id, matches, basename, future.v7_relativeSplatPath)
|
|
2964
2973
|
};
|
|
2965
2974
|
}
|
|
2966
2975
|
return convertHandlerResultToDataResult(result);
|
|
@@ -3342,14 +3351,19 @@ function createStaticHandler(routes, opts) {
|
|
|
3342
3351
|
* return it directly.
|
|
3343
3352
|
*
|
|
3344
3353
|
* - `opts.loadRouteIds` is an optional array of routeIds if you wish to only
|
|
3345
|
-
*
|
|
3354
|
+
* run a subset of route loaders on a GET request
|
|
3346
3355
|
* - `opts.requestContext` is an optional server context that will be passed
|
|
3347
|
-
*
|
|
3356
|
+
* to actions/loaders in the `context` parameter
|
|
3357
|
+
* - `opts.skipLoaderErrorBubbling` is an optional parameter that will prevent
|
|
3358
|
+
* the bubbling of loader errors which allows single-fetch-type implementations
|
|
3359
|
+
* where the client will handle the bubbling and we may need to return data
|
|
3360
|
+
* for the handling route
|
|
3348
3361
|
*/
|
|
3349
3362
|
async function query(request, _temp3) {
|
|
3350
3363
|
let {
|
|
3351
3364
|
loadRouteIds,
|
|
3352
|
-
requestContext
|
|
3365
|
+
requestContext,
|
|
3366
|
+
skipLoaderErrorBubbling
|
|
3353
3367
|
} = _temp3 === void 0 ? {} : _temp3;
|
|
3354
3368
|
let url = new URL(request.url);
|
|
3355
3369
|
let method = request.method;
|
|
@@ -3402,7 +3416,7 @@ function createStaticHandler(routes, opts) {
|
|
|
3402
3416
|
activeDeferreds: null
|
|
3403
3417
|
};
|
|
3404
3418
|
}
|
|
3405
|
-
let result = await queryImpl(request, location, matches, requestContext, loadRouteIds || null, null);
|
|
3419
|
+
let result = await queryImpl(request, location, matches, requestContext, loadRouteIds || null, skipLoaderErrorBubbling === true, null);
|
|
3406
3420
|
if (isResponse(result)) {
|
|
3407
3421
|
return result;
|
|
3408
3422
|
}
|
|
@@ -3474,7 +3488,7 @@ function createStaticHandler(routes, opts) {
|
|
|
3474
3488
|
pathname: location.pathname
|
|
3475
3489
|
});
|
|
3476
3490
|
}
|
|
3477
|
-
let result = await queryImpl(request, location, matches, requestContext, null, match);
|
|
3491
|
+
let result = await queryImpl(request, location, matches, requestContext, null, false, match);
|
|
3478
3492
|
if (isResponse(result)) {
|
|
3479
3493
|
return result;
|
|
3480
3494
|
}
|
|
@@ -3501,14 +3515,14 @@ function createStaticHandler(routes, opts) {
|
|
|
3501
3515
|
}
|
|
3502
3516
|
return undefined;
|
|
3503
3517
|
}
|
|
3504
|
-
async function queryImpl(request, location, matches, requestContext, loadRouteIds, routeMatch) {
|
|
3518
|
+
async function queryImpl(request, location, matches, requestContext, loadRouteIds, skipLoaderErrorBubbling, routeMatch) {
|
|
3505
3519
|
invariant(request.signal, "query()/queryRoute() requests must contain an AbortController signal");
|
|
3506
3520
|
try {
|
|
3507
3521
|
if (isMutationMethod(request.method.toLowerCase())) {
|
|
3508
|
-
let result = await submit(request, matches, routeMatch || getTargetMatch(matches, location), requestContext, loadRouteIds, routeMatch != null);
|
|
3522
|
+
let result = await submit(request, matches, routeMatch || getTargetMatch(matches, location), requestContext, loadRouteIds, skipLoaderErrorBubbling, routeMatch != null);
|
|
3509
3523
|
return result;
|
|
3510
3524
|
}
|
|
3511
|
-
let result = await loadRouteData(request, matches, requestContext, loadRouteIds, routeMatch);
|
|
3525
|
+
let result = await loadRouteData(request, matches, requestContext, loadRouteIds, skipLoaderErrorBubbling, routeMatch);
|
|
3512
3526
|
return isResponse(result) ? result : _extends({}, result, {
|
|
3513
3527
|
actionData: null,
|
|
3514
3528
|
actionHeaders: {}
|
|
@@ -3531,7 +3545,7 @@ function createStaticHandler(routes, opts) {
|
|
|
3531
3545
|
throw e;
|
|
3532
3546
|
}
|
|
3533
3547
|
}
|
|
3534
|
-
async function submit(request, matches, actionMatch, requestContext, loadRouteIds, isRouteRequest) {
|
|
3548
|
+
async function submit(request, matches, actionMatch, requestContext, loadRouteIds, skipLoaderErrorBubbling, isRouteRequest) {
|
|
3535
3549
|
let result;
|
|
3536
3550
|
if (!actionMatch.route.action && !actionMatch.route.lazy) {
|
|
3537
3551
|
let error = getInternalRouterError(405, {
|
|
@@ -3609,7 +3623,7 @@ function createStaticHandler(routes, opts) {
|
|
|
3609
3623
|
// Store off the pending error - we use it to determine which loaders
|
|
3610
3624
|
// to call and will commit it when we complete the navigation
|
|
3611
3625
|
let boundaryMatch = findNearestBoundary(matches, actionMatch.route.id);
|
|
3612
|
-
let context = await loadRouteData(loaderRequest, matches, requestContext, loadRouteIds, null, [boundaryMatch.route.id, result]);
|
|
3626
|
+
let context = await loadRouteData(loaderRequest, matches, requestContext, loadRouteIds, skipLoaderErrorBubbling, null, [boundaryMatch.route.id, result]);
|
|
3613
3627
|
|
|
3614
3628
|
// action status codes take precedence over loader status codes
|
|
3615
3629
|
return _extends({}, context, {
|
|
@@ -3620,7 +3634,7 @@ function createStaticHandler(routes, opts) {
|
|
|
3620
3634
|
} : {})
|
|
3621
3635
|
});
|
|
3622
3636
|
}
|
|
3623
|
-
let context = await loadRouteData(loaderRequest, matches, requestContext, loadRouteIds, null);
|
|
3637
|
+
let context = await loadRouteData(loaderRequest, matches, requestContext, loadRouteIds, skipLoaderErrorBubbling, null);
|
|
3624
3638
|
return _extends({}, context, {
|
|
3625
3639
|
actionData: {
|
|
3626
3640
|
[actionMatch.route.id]: result.data
|
|
@@ -3633,7 +3647,7 @@ function createStaticHandler(routes, opts) {
|
|
|
3633
3647
|
} : {}
|
|
3634
3648
|
});
|
|
3635
3649
|
}
|
|
3636
|
-
async function loadRouteData(request, matches, requestContext, loadRouteIds, routeMatch, pendingActionResult) {
|
|
3650
|
+
async function loadRouteData(request, matches, requestContext, loadRouteIds, skipLoaderErrorBubbling, routeMatch, pendingActionResult) {
|
|
3637
3651
|
let isRouteRequest = routeMatch != null;
|
|
3638
3652
|
|
|
3639
3653
|
// Short circuit if we have no loaders to run (queryRoute())
|
|
@@ -3673,7 +3687,7 @@ function createStaticHandler(routes, opts) {
|
|
|
3673
3687
|
|
|
3674
3688
|
// Process and commit output from loaders
|
|
3675
3689
|
let activeDeferreds = new Map();
|
|
3676
|
-
let context = processRouteLoaderData(matches, matchesToLoad, results, pendingActionResult, activeDeferreds);
|
|
3690
|
+
let context = processRouteLoaderData(matches, matchesToLoad, results, pendingActionResult, activeDeferreds, skipLoaderErrorBubbling);
|
|
3677
3691
|
|
|
3678
3692
|
// Add a null for any non-loader matches for proper revalidation on the client
|
|
3679
3693
|
let executedLoaders = new Set(matchesToLoad.map(match => match.route.id));
|
|
@@ -3694,8 +3708,9 @@ function createStaticHandler(routes, opts) {
|
|
|
3694
3708
|
let results = await callDataStrategyImpl(dataStrategyImpl, type, request, matchesToLoad, matches, manifest, mapRouteProperties, requestContext);
|
|
3695
3709
|
return await Promise.all(results.map((result, i) => {
|
|
3696
3710
|
if (isRedirectHandlerResult(result)) {
|
|
3711
|
+
let response = result.result;
|
|
3697
3712
|
// Throw redirects and let the server handle them with an HTTP redirect
|
|
3698
|
-
throw normalizeRelativeRoutingRedirectResponse(
|
|
3713
|
+
throw normalizeRelativeRoutingRedirectResponse(response, request, matchesToLoad[i].route.id, matches, basename, future.v7_relativeSplatPath);
|
|
3699
3714
|
}
|
|
3700
3715
|
if (isResponse(result.result) && isRouteRequest) {
|
|
3701
3716
|
// For SSR single-route requests, we want to hand Responses back
|
|
@@ -3937,7 +3952,8 @@ function getMatchesToLoad(history, state, matches, submission, location, isIniti
|
|
|
3937
3952
|
// Don't revalidate loaders by default after action 4xx/5xx responses
|
|
3938
3953
|
// when the flag is enabled. They can still opt-into revalidation via
|
|
3939
3954
|
// `shouldRevalidate` via `actionResult`
|
|
3940
|
-
let
|
|
3955
|
+
let actionStatus = pendingActionResult ? pendingActionResult[1].statusCode : undefined;
|
|
3956
|
+
let shouldSkipRevalidation = skipActionErrorRevalidation && actionStatus && actionStatus >= 400;
|
|
3941
3957
|
let navigationMatches = boundaryMatches.filter((match, index) => {
|
|
3942
3958
|
let {
|
|
3943
3959
|
route
|
|
@@ -3976,6 +3992,7 @@ function getMatchesToLoad(history, state, matches, submission, location, isIniti
|
|
|
3976
3992
|
nextParams: nextRouteMatch.params
|
|
3977
3993
|
}, submission, {
|
|
3978
3994
|
actionResult,
|
|
3995
|
+
unstable_actionStatus: actionStatus,
|
|
3979
3996
|
defaultShouldRevalidate: shouldSkipRevalidation ? false :
|
|
3980
3997
|
// Forced revalidation due to submission, useRevalidator, or X-Remix-Revalidate
|
|
3981
3998
|
isRevalidationRequired || currentUrl.pathname + currentUrl.search === nextUrl.pathname + nextUrl.search ||
|
|
@@ -4040,6 +4057,7 @@ function getMatchesToLoad(history, state, matches, submission, location, isIniti
|
|
|
4040
4057
|
nextParams: matches[matches.length - 1].params
|
|
4041
4058
|
}, submission, {
|
|
4042
4059
|
actionResult,
|
|
4060
|
+
unstable_actionStatus: actionStatus,
|
|
4043
4061
|
defaultShouldRevalidate: shouldSkipRevalidation ? false : isRevalidationRequired
|
|
4044
4062
|
}));
|
|
4045
4063
|
}
|
|
@@ -4163,13 +4181,7 @@ async function callDataStrategyImpl(dataStrategyImpl, type, request, matchesToLo
|
|
|
4163
4181
|
// over the execution of the loader/action
|
|
4164
4182
|
let resolve = handlerOverride => {
|
|
4165
4183
|
loadedMatches.add(match.route.id);
|
|
4166
|
-
return shouldLoad ? callLoaderOrAction(type, request, match, manifest, mapRouteProperties, handlerOverride, requestContext) :
|
|
4167
|
-
// TODO: What's the best thing to do here - return an empty "success" result?
|
|
4168
|
-
// Or return a success result with the current route loader/action data?
|
|
4169
|
-
// We strip these results out if the route didn't need to be revalidated in
|
|
4170
|
-
// `callDataStrategy` so it doesn't matter for us. It's more of a question
|
|
4171
|
-
// of whether exposing the current data to the user is useful?
|
|
4172
|
-
Promise.resolve({
|
|
4184
|
+
return shouldLoad ? callLoaderOrAction(type, request, match, manifest, mapRouteProperties, handlerOverride, requestContext) : Promise.resolve({
|
|
4173
4185
|
type: ResultType.data,
|
|
4174
4186
|
result: undefined
|
|
4175
4187
|
});
|
|
@@ -4185,8 +4197,6 @@ async function callDataStrategyImpl(dataStrategyImpl, type, request, matchesToLo
|
|
|
4185
4197
|
|
|
4186
4198
|
// Throw if any loadRoute implementations not called since they are what
|
|
4187
4199
|
// ensures a route is fully loaded
|
|
4188
|
-
// Throw if any loadRoute implementations not called since they are what
|
|
4189
|
-
// ensure a route is fully loaded
|
|
4190
4200
|
matches.forEach(m => invariant(loadedMatches.has(m.route.id), "`match.resolve()` was not called for route id \"" + m.route.id + "\". " + "You must call `match.resolve()` on every match passed to " + "`dataStrategy` to ensure all routes are properly loaded."));
|
|
4191
4201
|
|
|
4192
4202
|
// Filter out any middleware-only matches for which we didn't need to run handlers
|
|
@@ -4380,6 +4390,18 @@ function normalizeRelativeRoutingRedirectResponse(response, request, routeId, ma
|
|
|
4380
4390
|
}
|
|
4381
4391
|
return response;
|
|
4382
4392
|
}
|
|
4393
|
+
function normalizeRedirectLocation(location, currentUrl, basename) {
|
|
4394
|
+
if (ABSOLUTE_URL_REGEX.test(location)) {
|
|
4395
|
+
// Strip off the protocol+origin for same-origin + same-basename absolute redirects
|
|
4396
|
+
let normalizedLocation = location;
|
|
4397
|
+
let url = normalizedLocation.startsWith("//") ? new URL(currentUrl.protocol + normalizedLocation) : new URL(normalizedLocation);
|
|
4398
|
+
let isSameBasename = stripBasename(url.pathname, basename) != null;
|
|
4399
|
+
if (url.origin === currentUrl.origin && isSameBasename) {
|
|
4400
|
+
return url.pathname + url.search + url.hash;
|
|
4401
|
+
}
|
|
4402
|
+
}
|
|
4403
|
+
return location;
|
|
4404
|
+
}
|
|
4383
4405
|
|
|
4384
4406
|
// Utility method for creating the Request instances for loaders/actions during
|
|
4385
4407
|
// client-side navigations and fetches. During SSR we will always have a
|
|
@@ -4431,7 +4453,7 @@ function convertSearchParamsToFormData(searchParams) {
|
|
|
4431
4453
|
}
|
|
4432
4454
|
return formData;
|
|
4433
4455
|
}
|
|
4434
|
-
function processRouteLoaderData(matches, matchesToLoad, results, pendingActionResult, activeDeferreds) {
|
|
4456
|
+
function processRouteLoaderData(matches, matchesToLoad, results, pendingActionResult, activeDeferreds, skipLoaderErrorBubbling) {
|
|
4435
4457
|
// Fill in loaderData/errors from our loaders
|
|
4436
4458
|
let loaderData = {};
|
|
4437
4459
|
let errors = null;
|
|
@@ -4445,9 +4467,6 @@ function processRouteLoaderData(matches, matchesToLoad, results, pendingActionRe
|
|
|
4445
4467
|
let id = matchesToLoad[index].route.id;
|
|
4446
4468
|
invariant(!isRedirectResult(result), "Cannot handle redirect results in processLoaderData");
|
|
4447
4469
|
if (isErrorResult(result)) {
|
|
4448
|
-
// Look upwards from the matched route for the closest ancestor
|
|
4449
|
-
// error boundary, defaulting to the root match
|
|
4450
|
-
let boundaryMatch = findNearestBoundary(matches, id);
|
|
4451
4470
|
let error = result.error;
|
|
4452
4471
|
// If we have a pending action error, we report it at the highest-route
|
|
4453
4472
|
// that throws a loader error, and then clear it out to indicate that
|
|
@@ -4457,10 +4476,16 @@ function processRouteLoaderData(matches, matchesToLoad, results, pendingActionRe
|
|
|
4457
4476
|
pendingError = undefined;
|
|
4458
4477
|
}
|
|
4459
4478
|
errors = errors || {};
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4479
|
+
if (skipLoaderErrorBubbling) {
|
|
4480
|
+
errors[id] = error;
|
|
4481
|
+
} else {
|
|
4482
|
+
// Look upwards from the matched route for the closest ancestor error
|
|
4483
|
+
// boundary, defaulting to the root match. Prefer higher error values
|
|
4484
|
+
// if lower errors bubble to the same boundary
|
|
4485
|
+
let boundaryMatch = findNearestBoundary(matches, id);
|
|
4486
|
+
if (errors[boundaryMatch.route.id] == null) {
|
|
4487
|
+
errors[boundaryMatch.route.id] = error;
|
|
4488
|
+
}
|
|
4464
4489
|
}
|
|
4465
4490
|
|
|
4466
4491
|
// Clear our any prior loaderData for the throwing route
|
|
@@ -4521,7 +4546,8 @@ function processLoaderData(state, matches, matchesToLoad, results, pendingAction
|
|
|
4521
4546
|
let {
|
|
4522
4547
|
loaderData,
|
|
4523
4548
|
errors
|
|
4524
|
-
} = processRouteLoaderData(matches, matchesToLoad, results, pendingActionResult, activeDeferreds
|
|
4549
|
+
} = processRouteLoaderData(matches, matchesToLoad, results, pendingActionResult, activeDeferreds, false // This method is only called client side so we always want to bubble
|
|
4550
|
+
);
|
|
4525
4551
|
|
|
4526
4552
|
// Process results from our revalidating fetchers
|
|
4527
4553
|
for (let index = 0; index < revalidatingFetchers.length; index++) {
|