@remix-run/router 1.5.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/LICENSE.md +3 -2
- package/README.md +34 -6
- package/dist/router.cjs.js +214 -100
- package/dist/router.cjs.js.map +1 -1
- package/dist/router.d.ts +22 -12
- package/dist/router.js +214 -100
- package/dist/router.js.map +1 -1
- package/dist/router.umd.js +214 -100
- 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 +20 -3
- package/package.json +1 -1
- package/router.ts +301 -132
- package/utils.ts +25 -6
package/dist/router.cjs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @remix-run/router v1.
|
|
2
|
+
* @remix-run/router v1.6.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -576,7 +576,7 @@ function isIndexRoute(route) {
|
|
|
576
576
|
// solely with AgnosticDataRouteObject's within the Router
|
|
577
577
|
|
|
578
578
|
|
|
579
|
-
function convertRoutesToDataRoutes(routes,
|
|
579
|
+
function convertRoutesToDataRoutes(routes, mapRouteProperties, parentPath, manifest) {
|
|
580
580
|
if (parentPath === void 0) {
|
|
581
581
|
parentPath = [];
|
|
582
582
|
}
|
|
@@ -592,24 +592,22 @@ function convertRoutesToDataRoutes(routes, detectErrorBoundary, parentPath, mani
|
|
|
592
592
|
invariant(!manifest[id], "Found a route id collision on id \"" + id + "\". Route " + "id's must be globally unique within Data Router usages");
|
|
593
593
|
|
|
594
594
|
if (isIndexRoute(route)) {
|
|
595
|
-
let indexRoute = _extends({}, route, {
|
|
596
|
-
hasErrorBoundary: detectErrorBoundary(route),
|
|
595
|
+
let indexRoute = _extends({}, route, mapRouteProperties(route), {
|
|
597
596
|
id
|
|
598
597
|
});
|
|
599
598
|
|
|
600
599
|
manifest[id] = indexRoute;
|
|
601
600
|
return indexRoute;
|
|
602
601
|
} else {
|
|
603
|
-
let pathOrLayoutRoute = _extends({}, route, {
|
|
602
|
+
let pathOrLayoutRoute = _extends({}, route, mapRouteProperties(route), {
|
|
604
603
|
id,
|
|
605
|
-
hasErrorBoundary: detectErrorBoundary(route),
|
|
606
604
|
children: undefined
|
|
607
605
|
});
|
|
608
606
|
|
|
609
607
|
manifest[id] = pathOrLayoutRoute;
|
|
610
608
|
|
|
611
609
|
if (route.children) {
|
|
612
|
-
pathOrLayoutRoute.children = convertRoutesToDataRoutes(route.children,
|
|
610
|
+
pathOrLayoutRoute.children = convertRoutesToDataRoutes(route.children, mapRouteProperties, treePath, manifest);
|
|
613
611
|
}
|
|
614
612
|
|
|
615
613
|
return pathOrLayoutRoute;
|
|
@@ -1471,7 +1469,9 @@ const ABSOLUTE_URL_REGEX = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;
|
|
|
1471
1469
|
const isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined";
|
|
1472
1470
|
const isServer = !isBrowser;
|
|
1473
1471
|
|
|
1474
|
-
const
|
|
1472
|
+
const defaultMapRouteProperties = route => ({
|
|
1473
|
+
hasErrorBoundary: Boolean(route.hasErrorBoundary)
|
|
1474
|
+
}); //#endregion
|
|
1475
1475
|
////////////////////////////////////////////////////////////////////////////////
|
|
1476
1476
|
//#region createRouter
|
|
1477
1477
|
////////////////////////////////////////////////////////////////////////////////
|
|
@@ -1483,15 +1483,31 @@ const defaultDetectErrorBoundary = route => Boolean(route.hasErrorBoundary); //#
|
|
|
1483
1483
|
|
|
1484
1484
|
function createRouter(init) {
|
|
1485
1485
|
invariant(init.routes.length > 0, "You must provide a non-empty routes array to createRouter");
|
|
1486
|
-
let
|
|
1486
|
+
let mapRouteProperties;
|
|
1487
|
+
|
|
1488
|
+
if (init.mapRouteProperties) {
|
|
1489
|
+
mapRouteProperties = init.mapRouteProperties;
|
|
1490
|
+
} else if (init.detectErrorBoundary) {
|
|
1491
|
+
// If they are still using the deprecated version, wrap it with the new API
|
|
1492
|
+
let detectErrorBoundary = init.detectErrorBoundary;
|
|
1493
|
+
|
|
1494
|
+
mapRouteProperties = route => ({
|
|
1495
|
+
hasErrorBoundary: detectErrorBoundary(route)
|
|
1496
|
+
});
|
|
1497
|
+
} else {
|
|
1498
|
+
mapRouteProperties = defaultMapRouteProperties;
|
|
1499
|
+
} // Routes keyed by ID
|
|
1500
|
+
|
|
1487
1501
|
|
|
1488
1502
|
let manifest = {}; // Routes in tree format for matching
|
|
1489
1503
|
|
|
1490
|
-
let dataRoutes = convertRoutesToDataRoutes(init.routes,
|
|
1491
|
-
let inFlightDataRoutes;
|
|
1504
|
+
let dataRoutes = convertRoutesToDataRoutes(init.routes, mapRouteProperties, undefined, manifest);
|
|
1505
|
+
let inFlightDataRoutes;
|
|
1506
|
+
let basename = init.basename || "/"; // Config driven behavior flags
|
|
1492
1507
|
|
|
1493
1508
|
let future = _extends({
|
|
1494
|
-
v7_normalizeFormMethod: false
|
|
1509
|
+
v7_normalizeFormMethod: false,
|
|
1510
|
+
v7_prependBasename: false
|
|
1495
1511
|
}, init.future); // Cleanup function for history
|
|
1496
1512
|
|
|
1497
1513
|
|
|
@@ -1511,7 +1527,7 @@ function createRouter(init) {
|
|
|
1511
1527
|
// SSR did the initial scroll restoration.
|
|
1512
1528
|
|
|
1513
1529
|
let initialScrollRestored = init.hydrationData != null;
|
|
1514
|
-
let initialMatches = matchRoutes(dataRoutes, init.history.location,
|
|
1530
|
+
let initialMatches = matchRoutes(dataRoutes, init.history.location, basename);
|
|
1515
1531
|
let initialErrors = null;
|
|
1516
1532
|
|
|
1517
1533
|
if (initialMatches == null) {
|
|
@@ -1563,7 +1579,7 @@ function createRouter(init) {
|
|
|
1563
1579
|
|
|
1564
1580
|
let isUninterruptedRevalidation = false; // Use this internal flag to force revalidation of all loaders:
|
|
1565
1581
|
// - submissions (completed or interrupted)
|
|
1566
|
-
// -
|
|
1582
|
+
// - useRevalidator()
|
|
1567
1583
|
// - X-Remix-Revalidate (from redirect)
|
|
1568
1584
|
|
|
1569
1585
|
let isRevalidationRequired = false; // Use this internal array to capture routes that require revalidation due
|
|
@@ -1582,7 +1598,7 @@ function createRouter(init) {
|
|
|
1582
1598
|
|
|
1583
1599
|
let pendingNavigationLoadId = -1; // Fetchers that triggered data reloads as a result of their actions
|
|
1584
1600
|
|
|
1585
|
-
let fetchReloadIds = new Map(); // Fetchers that triggered redirect navigations
|
|
1601
|
+
let fetchReloadIds = new Map(); // Fetchers that triggered redirect navigations
|
|
1586
1602
|
|
|
1587
1603
|
let fetchRedirectIds = new Set(); // Most recent href/match for fetcher.load calls for fetchers
|
|
1588
1604
|
|
|
@@ -1779,11 +1795,12 @@ function createRouter(init) {
|
|
|
1779
1795
|
return;
|
|
1780
1796
|
}
|
|
1781
1797
|
|
|
1798
|
+
let normalizedPath = normalizeTo(state.location, state.matches, basename, future.v7_prependBasename, to, opts == null ? void 0 : opts.fromRouteId, opts == null ? void 0 : opts.relative);
|
|
1782
1799
|
let {
|
|
1783
1800
|
path,
|
|
1784
1801
|
submission,
|
|
1785
1802
|
error
|
|
1786
|
-
} = normalizeNavigateOptions(
|
|
1803
|
+
} = normalizeNavigateOptions(future.v7_normalizeFormMethod, false, normalizedPath, opts);
|
|
1787
1804
|
let currentLocation = state.location;
|
|
1788
1805
|
let nextLocation = createLocation(state.location, path, opts && opts.state); // When using navigate as a PUSH/REPLACE we aren't reading an already-encoded
|
|
1789
1806
|
// URL from window.location, so we need to encode it here so the behavior
|
|
@@ -1899,7 +1916,7 @@ function createRouter(init) {
|
|
|
1899
1916
|
pendingPreventScrollReset = (opts && opts.preventScrollReset) === true;
|
|
1900
1917
|
let routesToUse = inFlightDataRoutes || dataRoutes;
|
|
1901
1918
|
let loadingNavigation = opts && opts.overrideNavigation;
|
|
1902
|
-
let matches = matchRoutes(routesToUse, location,
|
|
1919
|
+
let matches = matchRoutes(routesToUse, location, basename); // Short circuit with a 404 on the root error boundary if we match nothing
|
|
1903
1920
|
|
|
1904
1921
|
if (!matches) {
|
|
1905
1922
|
let error = getInternalRouterError(404, {
|
|
@@ -2022,7 +2039,7 @@ function createRouter(init) {
|
|
|
2022
2039
|
})
|
|
2023
2040
|
};
|
|
2024
2041
|
} else {
|
|
2025
|
-
result = await callLoaderOrAction("action", request, actionMatch, matches, manifest,
|
|
2042
|
+
result = await callLoaderOrAction("action", request, actionMatch, matches, manifest, mapRouteProperties, basename);
|
|
2026
2043
|
|
|
2027
2044
|
if (request.signal.aborted) {
|
|
2028
2045
|
return {
|
|
@@ -2114,13 +2131,14 @@ function createRouter(init) {
|
|
|
2114
2131
|
formEncType: loadingNavigation.formEncType
|
|
2115
2132
|
} : undefined;
|
|
2116
2133
|
let routesToUse = inFlightDataRoutes || dataRoutes;
|
|
2117
|
-
let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, activeSubmission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, fetchLoadMatches, routesToUse,
|
|
2134
|
+
let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, activeSubmission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, fetchLoadMatches, routesToUse, basename, pendingActionData, pendingError); // Cancel pending deferreds for no-longer-matched routes or routes we're
|
|
2118
2135
|
// about to reload. Note that if this is an action reload we would have
|
|
2119
2136
|
// already cancelled all pending deferreds so this would be a no-op
|
|
2120
2137
|
|
|
2121
2138
|
cancelActiveDeferreds(routeId => !(matches && matches.some(m => m.route.id === routeId)) || matchesToLoad && matchesToLoad.some(m => m.route.id === routeId)); // Short circuit if we have no loaders to run
|
|
2122
2139
|
|
|
2123
2140
|
if (matchesToLoad.length === 0 && revalidatingFetchers.length === 0) {
|
|
2141
|
+
let updatedFetchers = markFetchRedirectsDone();
|
|
2124
2142
|
completeNavigation(location, _extends({
|
|
2125
2143
|
matches,
|
|
2126
2144
|
loaderData: {},
|
|
@@ -2128,6 +2146,8 @@ function createRouter(init) {
|
|
|
2128
2146
|
errors: pendingError || null
|
|
2129
2147
|
}, pendingActionData ? {
|
|
2130
2148
|
actionData: pendingActionData
|
|
2149
|
+
} : {}, updatedFetchers ? {
|
|
2150
|
+
fetchers: new Map(state.fetchers)
|
|
2131
2151
|
} : {}));
|
|
2132
2152
|
return {
|
|
2133
2153
|
shortCircuited: true
|
|
@@ -2165,7 +2185,21 @@ function createRouter(init) {
|
|
|
2165
2185
|
}
|
|
2166
2186
|
|
|
2167
2187
|
pendingNavigationLoadId = ++incrementingLoadId;
|
|
2168
|
-
revalidatingFetchers.forEach(rf =>
|
|
2188
|
+
revalidatingFetchers.forEach(rf => {
|
|
2189
|
+
if (rf.controller) {
|
|
2190
|
+
// Fetchers use an independent AbortController so that aborting a fetcher
|
|
2191
|
+
// (via deleteFetcher) does not abort the triggering navigation that
|
|
2192
|
+
// triggered the revalidation
|
|
2193
|
+
fetchControllers.set(rf.key, rf.controller);
|
|
2194
|
+
}
|
|
2195
|
+
}); // Proxy navigation abort through to revalidation fetchers
|
|
2196
|
+
|
|
2197
|
+
let abortPendingFetchRevalidations = () => revalidatingFetchers.forEach(f => abortFetcher(f.key));
|
|
2198
|
+
|
|
2199
|
+
if (pendingNavigationController) {
|
|
2200
|
+
pendingNavigationController.signal.addEventListener("abort", abortPendingFetchRevalidations);
|
|
2201
|
+
}
|
|
2202
|
+
|
|
2169
2203
|
let {
|
|
2170
2204
|
results,
|
|
2171
2205
|
loaderResults,
|
|
@@ -2181,6 +2215,10 @@ function createRouter(init) {
|
|
|
2181
2215
|
// reassigned to new controllers for the next navigation
|
|
2182
2216
|
|
|
2183
2217
|
|
|
2218
|
+
if (pendingNavigationController) {
|
|
2219
|
+
pendingNavigationController.signal.removeEventListener("abort", abortPendingFetchRevalidations);
|
|
2220
|
+
}
|
|
2221
|
+
|
|
2184
2222
|
revalidatingFetchers.forEach(rf => fetchControllers.delete(rf.key)); // If any loaders returned a redirect Response, start a new REPLACE navigation
|
|
2185
2223
|
|
|
2186
2224
|
let redirect = findRedirect(results);
|
|
@@ -2210,12 +2248,13 @@ function createRouter(init) {
|
|
|
2210
2248
|
}
|
|
2211
2249
|
});
|
|
2212
2250
|
});
|
|
2213
|
-
markFetchRedirectsDone();
|
|
2251
|
+
let updatedFetchers = markFetchRedirectsDone();
|
|
2214
2252
|
let didAbortFetchLoads = abortStaleFetchLoads(pendingNavigationLoadId);
|
|
2253
|
+
let shouldUpdateFetchers = updatedFetchers || didAbortFetchLoads || revalidatingFetchers.length > 0;
|
|
2215
2254
|
return _extends({
|
|
2216
2255
|
loaderData,
|
|
2217
2256
|
errors
|
|
2218
|
-
},
|
|
2257
|
+
}, shouldUpdateFetchers ? {
|
|
2219
2258
|
fetchers: new Map(state.fetchers)
|
|
2220
2259
|
} : {});
|
|
2221
2260
|
}
|
|
@@ -2232,11 +2271,12 @@ function createRouter(init) {
|
|
|
2232
2271
|
|
|
2233
2272
|
if (fetchControllers.has(key)) abortFetcher(key);
|
|
2234
2273
|
let routesToUse = inFlightDataRoutes || dataRoutes;
|
|
2235
|
-
let
|
|
2274
|
+
let normalizedPath = normalizeTo(state.location, state.matches, basename, future.v7_prependBasename, href, routeId, opts == null ? void 0 : opts.relative);
|
|
2275
|
+
let matches = matchRoutes(routesToUse, normalizedPath, basename);
|
|
2236
2276
|
|
|
2237
2277
|
if (!matches) {
|
|
2238
2278
|
setFetcherError(key, routeId, getInternalRouterError(404, {
|
|
2239
|
-
pathname:
|
|
2279
|
+
pathname: normalizedPath
|
|
2240
2280
|
}));
|
|
2241
2281
|
return;
|
|
2242
2282
|
}
|
|
@@ -2244,7 +2284,7 @@ function createRouter(init) {
|
|
|
2244
2284
|
let {
|
|
2245
2285
|
path,
|
|
2246
2286
|
submission
|
|
2247
|
-
} = normalizeNavigateOptions(
|
|
2287
|
+
} = normalizeNavigateOptions(future.v7_normalizeFormMethod, true, normalizedPath, opts);
|
|
2248
2288
|
let match = getTargetMatch(matches, path);
|
|
2249
2289
|
pendingPreventScrollReset = (opts && opts.preventScrollReset) === true;
|
|
2250
2290
|
|
|
@@ -2296,7 +2336,7 @@ function createRouter(init) {
|
|
|
2296
2336
|
let abortController = new AbortController();
|
|
2297
2337
|
let fetchRequest = createClientSideRequest(init.history, path, abortController.signal, submission);
|
|
2298
2338
|
fetchControllers.set(key, abortController);
|
|
2299
|
-
let actionResult = await callLoaderOrAction("action", fetchRequest, match, requestMatches, manifest,
|
|
2339
|
+
let actionResult = await callLoaderOrAction("action", fetchRequest, match, requestMatches, manifest, mapRouteProperties, basename);
|
|
2300
2340
|
|
|
2301
2341
|
if (fetchRequest.signal.aborted) {
|
|
2302
2342
|
// We can delete this so long as we weren't aborted by ou our own fetcher
|
|
@@ -2346,7 +2386,7 @@ function createRouter(init) {
|
|
|
2346
2386
|
let nextLocation = state.navigation.location || state.location;
|
|
2347
2387
|
let revalidationRequest = createClientSideRequest(init.history, nextLocation, abortController.signal);
|
|
2348
2388
|
let routesToUse = inFlightDataRoutes || dataRoutes;
|
|
2349
|
-
let matches = state.navigation.state !== "idle" ? matchRoutes(routesToUse, state.navigation.location,
|
|
2389
|
+
let matches = state.navigation.state !== "idle" ? matchRoutes(routesToUse, state.navigation.location, basename) : state.matches;
|
|
2350
2390
|
invariant(matches, "Didn't find any matches after fetcher action");
|
|
2351
2391
|
let loadId = ++incrementingLoadId;
|
|
2352
2392
|
fetchReloadIds.set(key, loadId);
|
|
@@ -2359,7 +2399,7 @@ function createRouter(init) {
|
|
|
2359
2399
|
});
|
|
2360
2400
|
|
|
2361
2401
|
state.fetchers.set(key, loadFetcher);
|
|
2362
|
-
let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, submission, nextLocation, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, fetchLoadMatches, routesToUse,
|
|
2402
|
+
let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, submission, nextLocation, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, fetchLoadMatches, routesToUse, basename, {
|
|
2363
2403
|
[match.route.id]: actionResult.data
|
|
2364
2404
|
}, undefined // No need to send through errors since we short circuit above
|
|
2365
2405
|
); // Put all revalidating fetchers into the loading state, except for the
|
|
@@ -2379,11 +2419,18 @@ function createRouter(init) {
|
|
|
2379
2419
|
" _hasFetcherDoneAnything ": true
|
|
2380
2420
|
};
|
|
2381
2421
|
state.fetchers.set(staleKey, revalidatingFetcher);
|
|
2382
|
-
|
|
2422
|
+
|
|
2423
|
+
if (rf.controller) {
|
|
2424
|
+
fetchControllers.set(staleKey, rf.controller);
|
|
2425
|
+
}
|
|
2383
2426
|
});
|
|
2384
2427
|
updateState({
|
|
2385
2428
|
fetchers: new Map(state.fetchers)
|
|
2386
2429
|
});
|
|
2430
|
+
|
|
2431
|
+
let abortPendingFetchRevalidations = () => revalidatingFetchers.forEach(rf => abortFetcher(rf.key));
|
|
2432
|
+
|
|
2433
|
+
abortController.signal.addEventListener("abort", abortPendingFetchRevalidations);
|
|
2387
2434
|
let {
|
|
2388
2435
|
results,
|
|
2389
2436
|
loaderResults,
|
|
@@ -2394,6 +2441,7 @@ function createRouter(init) {
|
|
|
2394
2441
|
return;
|
|
2395
2442
|
}
|
|
2396
2443
|
|
|
2444
|
+
abortController.signal.removeEventListener("abort", abortPendingFetchRevalidations);
|
|
2397
2445
|
fetchReloadIds.delete(key);
|
|
2398
2446
|
fetchControllers.delete(key);
|
|
2399
2447
|
revalidatingFetchers.forEach(r => fetchControllers.delete(r.key));
|
|
@@ -2468,14 +2516,14 @@ function createRouter(init) {
|
|
|
2468
2516
|
let abortController = new AbortController();
|
|
2469
2517
|
let fetchRequest = createClientSideRequest(init.history, path, abortController.signal);
|
|
2470
2518
|
fetchControllers.set(key, abortController);
|
|
2471
|
-
let result = await callLoaderOrAction("loader", fetchRequest, match, matches, manifest,
|
|
2519
|
+
let result = await callLoaderOrAction("loader", fetchRequest, match, matches, manifest, mapRouteProperties, basename); // Deferred isn't supported for fetcher loads, await everything and treat it
|
|
2472
2520
|
// as a normal load. resolveDeferredData will return undefined if this
|
|
2473
2521
|
// fetcher gets aborted, so we just leave result untouched and short circuit
|
|
2474
2522
|
// below if that happens
|
|
2475
2523
|
|
|
2476
2524
|
if (isDeferredResult(result)) {
|
|
2477
2525
|
result = (await resolveDeferredData(result, fetchRequest.signal, true)) || result;
|
|
2478
|
-
} // We can delete this so long as we weren't aborted by
|
|
2526
|
+
} // We can delete this so long as we weren't aborted by our our own fetcher
|
|
2479
2527
|
// re-load which would have put _new_ controller is in fetchControllers
|
|
2480
2528
|
|
|
2481
2529
|
|
|
@@ -2489,6 +2537,7 @@ function createRouter(init) {
|
|
|
2489
2537
|
|
|
2490
2538
|
|
|
2491
2539
|
if (isRedirectResult(result)) {
|
|
2540
|
+
fetchRedirectIds.add(key);
|
|
2492
2541
|
await startRedirectNavigation(state, result);
|
|
2493
2542
|
return;
|
|
2494
2543
|
} // Process any non-redirect errors thrown
|
|
@@ -2569,7 +2618,7 @@ function createRouter(init) {
|
|
|
2569
2618
|
|
|
2570
2619
|
if (ABSOLUTE_URL_REGEX.test(redirect.location) && isBrowser && typeof ((_window = window) == null ? void 0 : _window.location) !== "undefined") {
|
|
2571
2620
|
let url = init.history.createURL(redirect.location);
|
|
2572
|
-
let isDifferentBasename = stripBasename(url.pathname,
|
|
2621
|
+
let isDifferentBasename = stripBasename(url.pathname, basename) == null;
|
|
2573
2622
|
|
|
2574
2623
|
if (window.location.origin !== url.origin || isDifferentBasename) {
|
|
2575
2624
|
if (replace) {
|
|
@@ -2653,9 +2702,9 @@ function createRouter(init) {
|
|
|
2653
2702
|
// Call all navigation loaders and revalidating fetcher loaders in parallel,
|
|
2654
2703
|
// then slice off the results into separate arrays so we can handle them
|
|
2655
2704
|
// accordingly
|
|
2656
|
-
let results = await Promise.all([...matchesToLoad.map(match => callLoaderOrAction("loader", request, match, matches, manifest,
|
|
2657
|
-
if (f.matches && f.match) {
|
|
2658
|
-
return callLoaderOrAction("loader", createClientSideRequest(init.history, f.path,
|
|
2705
|
+
let results = await Promise.all([...matchesToLoad.map(match => callLoaderOrAction("loader", request, match, matches, manifest, mapRouteProperties, basename)), ...fetchersToLoad.map(f => {
|
|
2706
|
+
if (f.matches && f.match && f.controller) {
|
|
2707
|
+
return callLoaderOrAction("loader", createClientSideRequest(init.history, f.path, f.controller.signal), f.match, f.matches, manifest, mapRouteProperties, basename);
|
|
2659
2708
|
} else {
|
|
2660
2709
|
let error = {
|
|
2661
2710
|
type: ResultType.error,
|
|
@@ -2668,7 +2717,7 @@ function createRouter(init) {
|
|
|
2668
2717
|
})]);
|
|
2669
2718
|
let loaderResults = results.slice(0, matchesToLoad.length);
|
|
2670
2719
|
let fetcherResults = results.slice(matchesToLoad.length);
|
|
2671
|
-
await Promise.all([resolveDeferredResults(currentMatches, matchesToLoad, loaderResults, request.signal, false, state.loaderData), resolveDeferredResults(currentMatches, fetchersToLoad.map(f => f.match), fetcherResults,
|
|
2720
|
+
await Promise.all([resolveDeferredResults(currentMatches, matchesToLoad, loaderResults, loaderResults.map(() => request.signal), false, state.loaderData), resolveDeferredResults(currentMatches, fetchersToLoad.map(f => f.match), fetcherResults, fetchersToLoad.map(f => f.controller ? f.controller.signal : null), true)]);
|
|
2672
2721
|
return {
|
|
2673
2722
|
results,
|
|
2674
2723
|
loaderResults,
|
|
@@ -2735,6 +2784,7 @@ function createRouter(init) {
|
|
|
2735
2784
|
|
|
2736
2785
|
function markFetchRedirectsDone() {
|
|
2737
2786
|
let doneKeys = [];
|
|
2787
|
+
let updatedFetchers = false;
|
|
2738
2788
|
|
|
2739
2789
|
for (let key of fetchRedirectIds) {
|
|
2740
2790
|
let fetcher = state.fetchers.get(key);
|
|
@@ -2743,10 +2793,12 @@ function createRouter(init) {
|
|
|
2743
2793
|
if (fetcher.state === "loading") {
|
|
2744
2794
|
fetchRedirectIds.delete(key);
|
|
2745
2795
|
doneKeys.push(key);
|
|
2796
|
+
updatedFetchers = true;
|
|
2746
2797
|
}
|
|
2747
2798
|
}
|
|
2748
2799
|
|
|
2749
2800
|
markFetchersDone(doneKeys);
|
|
2801
|
+
return updatedFetchers;
|
|
2750
2802
|
}
|
|
2751
2803
|
|
|
2752
2804
|
function abortStaleFetchLoads(landedId) {
|
|
@@ -2906,7 +2958,7 @@ function createRouter(init) {
|
|
|
2906
2958
|
|
|
2907
2959
|
router = {
|
|
2908
2960
|
get basename() {
|
|
2909
|
-
return
|
|
2961
|
+
return basename;
|
|
2910
2962
|
},
|
|
2911
2963
|
|
|
2912
2964
|
get state() {
|
|
@@ -2948,9 +3000,23 @@ const UNSAFE_DEFERRED_SYMBOL = Symbol("deferred");
|
|
|
2948
3000
|
function createStaticHandler(routes, opts) {
|
|
2949
3001
|
invariant(routes.length > 0, "You must provide a non-empty routes array to createStaticHandler");
|
|
2950
3002
|
let manifest = {};
|
|
2951
|
-
let detectErrorBoundary = (opts == null ? void 0 : opts.detectErrorBoundary) || defaultDetectErrorBoundary;
|
|
2952
|
-
let dataRoutes = convertRoutesToDataRoutes(routes, detectErrorBoundary, undefined, manifest);
|
|
2953
3003
|
let basename = (opts ? opts.basename : null) || "/";
|
|
3004
|
+
let mapRouteProperties;
|
|
3005
|
+
|
|
3006
|
+
if (opts != null && opts.mapRouteProperties) {
|
|
3007
|
+
mapRouteProperties = opts.mapRouteProperties;
|
|
3008
|
+
} else if (opts != null && opts.detectErrorBoundary) {
|
|
3009
|
+
// If they are still using the deprecated version, wrap it with the new API
|
|
3010
|
+
let detectErrorBoundary = opts.detectErrorBoundary;
|
|
3011
|
+
|
|
3012
|
+
mapRouteProperties = route => ({
|
|
3013
|
+
hasErrorBoundary: detectErrorBoundary(route)
|
|
3014
|
+
});
|
|
3015
|
+
} else {
|
|
3016
|
+
mapRouteProperties = defaultMapRouteProperties;
|
|
3017
|
+
}
|
|
3018
|
+
|
|
3019
|
+
let dataRoutes = convertRoutesToDataRoutes(routes, mapRouteProperties, undefined, manifest);
|
|
2954
3020
|
/**
|
|
2955
3021
|
* The query() method is intended for document requests, in which we want to
|
|
2956
3022
|
* call an optional action and potentially multiple loaders for all nested
|
|
@@ -3187,7 +3253,7 @@ function createStaticHandler(routes, opts) {
|
|
|
3187
3253
|
error
|
|
3188
3254
|
};
|
|
3189
3255
|
} else {
|
|
3190
|
-
result = await callLoaderOrAction("action", request, actionMatch, matches, manifest,
|
|
3256
|
+
result = await callLoaderOrAction("action", request, actionMatch, matches, manifest, mapRouteProperties, basename, true, isRouteRequest, requestContext);
|
|
3191
3257
|
|
|
3192
3258
|
if (request.signal.aborted) {
|
|
3193
3259
|
let method = isRouteRequest ? "queryRoute" : "query";
|
|
@@ -3310,7 +3376,7 @@ function createStaticHandler(routes, opts) {
|
|
|
3310
3376
|
};
|
|
3311
3377
|
}
|
|
3312
3378
|
|
|
3313
|
-
let results = await Promise.all([...matchesToLoad.map(match => callLoaderOrAction("loader", request, match, matches, manifest,
|
|
3379
|
+
let results = await Promise.all([...matchesToLoad.map(match => callLoaderOrAction("loader", request, match, matches, manifest, mapRouteProperties, basename, true, isRouteRequest, requestContext))]);
|
|
3314
3380
|
|
|
3315
3381
|
if (request.signal.aborted) {
|
|
3316
3382
|
let method = isRouteRequest ? "queryRoute" : "query";
|
|
@@ -3361,17 +3427,62 @@ function getStaticContextFromError(routes, context, error) {
|
|
|
3361
3427
|
|
|
3362
3428
|
function isSubmissionNavigation(opts) {
|
|
3363
3429
|
return opts != null && "formData" in opts;
|
|
3364
|
-
}
|
|
3365
|
-
// URLSearchParams so they behave identically to links with query params
|
|
3430
|
+
}
|
|
3366
3431
|
|
|
3432
|
+
function normalizeTo(location, matches, basename, prependBasename, to, fromRouteId, relative) {
|
|
3433
|
+
let contextualMatches;
|
|
3434
|
+
let activeRouteMatch;
|
|
3367
3435
|
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3436
|
+
if (fromRouteId != null && relative !== "path") {
|
|
3437
|
+
// Grab matches up to the calling route so our route-relative logic is
|
|
3438
|
+
// relative to the correct source route. When using relative:path,
|
|
3439
|
+
// fromRouteId is ignored since that is always relative to the current
|
|
3440
|
+
// location path
|
|
3441
|
+
contextualMatches = [];
|
|
3442
|
+
|
|
3443
|
+
for (let match of matches) {
|
|
3444
|
+
contextualMatches.push(match);
|
|
3445
|
+
|
|
3446
|
+
if (match.route.id === fromRouteId) {
|
|
3447
|
+
activeRouteMatch = match;
|
|
3448
|
+
break;
|
|
3449
|
+
}
|
|
3450
|
+
}
|
|
3451
|
+
} else {
|
|
3452
|
+
contextualMatches = matches;
|
|
3453
|
+
activeRouteMatch = matches[matches.length - 1];
|
|
3454
|
+
} // Resolve the relative path
|
|
3455
|
+
|
|
3456
|
+
|
|
3457
|
+
let path = resolveTo(to ? to : ".", getPathContributingMatches(contextualMatches).map(m => m.pathnameBase), location.pathname, relative === "path"); // When `to` is not specified we inherit search/hash from the current
|
|
3458
|
+
// location, unlike when to="." and we just inherit the path.
|
|
3459
|
+
// See https://github.com/remix-run/remix/issues/927
|
|
3460
|
+
|
|
3461
|
+
if (to == null) {
|
|
3462
|
+
path.search = location.search;
|
|
3463
|
+
path.hash = location.hash;
|
|
3464
|
+
} // Add an ?index param for matched index routes if we don't already have one
|
|
3465
|
+
|
|
3466
|
+
|
|
3467
|
+
if ((to == null || to === "" || to === ".") && activeRouteMatch && activeRouteMatch.route.index && !hasNakedIndexQuery(path.search)) {
|
|
3468
|
+
path.search = path.search ? path.search.replace(/^\?/, "?index&") : "?index";
|
|
3469
|
+
} // If we're operating within a basename, prepend it to the pathname. If
|
|
3470
|
+
// this is a root navigation, then just use the raw basename which allows
|
|
3471
|
+
// the basename to have full control over the presence of a trailing slash
|
|
3472
|
+
// on root actions
|
|
3473
|
+
|
|
3474
|
+
|
|
3475
|
+
if (prependBasename && basename !== "/") {
|
|
3476
|
+
path.pathname = path.pathname === "/" ? basename : joinPaths([basename, path.pathname]);
|
|
3371
3477
|
}
|
|
3372
3478
|
|
|
3373
|
-
|
|
3479
|
+
return createPath(path);
|
|
3480
|
+
} // Normalize navigation options by converting formMethod=GET formData objects to
|
|
3481
|
+
// URLSearchParams so they behave identically to links with query params
|
|
3482
|
+
|
|
3374
3483
|
|
|
3484
|
+
function normalizeNavigateOptions(normalizeFormMethod, isFetcher, path, opts) {
|
|
3485
|
+
// Return location verbatim on non-submission navigations
|
|
3375
3486
|
if (!opts || !isSubmissionNavigation(opts)) {
|
|
3376
3487
|
return {
|
|
3377
3488
|
path
|
|
@@ -3393,7 +3504,7 @@ function normalizeNavigateOptions(to, future, opts, isFetcher) {
|
|
|
3393
3504
|
if (opts.formData) {
|
|
3394
3505
|
let formMethod = opts.formMethod || "get";
|
|
3395
3506
|
submission = {
|
|
3396
|
-
formMethod:
|
|
3507
|
+
formMethod: normalizeFormMethod ? formMethod.toUpperCase() : formMethod.toLowerCase(),
|
|
3397
3508
|
formAction: stripHashFromPath(path),
|
|
3398
3509
|
formEncType: opts && opts.formEncType || "application/x-www-form-urlencoded",
|
|
3399
3510
|
formData: opts.formData
|
|
@@ -3409,9 +3520,9 @@ function normalizeNavigateOptions(to, future, opts, isFetcher) {
|
|
|
3409
3520
|
|
|
3410
3521
|
|
|
3411
3522
|
let parsedPath = parsePath(path);
|
|
3412
|
-
let searchParams = convertFormDataToSearchParams(opts.formData); //
|
|
3413
|
-
//
|
|
3414
|
-
// any incoming ?index params
|
|
3523
|
+
let searchParams = convertFormDataToSearchParams(opts.formData); // On GET navigation submissions we can drop the ?index param from the
|
|
3524
|
+
// resulting location since all loaders will run. But fetcher GET submissions
|
|
3525
|
+
// only run a single loader so we need to preserve any incoming ?index params
|
|
3415
3526
|
|
|
3416
3527
|
if (isFetcher && parsedPath.search && hasNakedIndexQuery(parsedPath.search)) {
|
|
3417
3528
|
searchParams.append("index", "");
|
|
@@ -3443,11 +3554,7 @@ function getLoaderMatchesUntilBoundary(matches, boundaryId) {
|
|
|
3443
3554
|
function getMatchesToLoad(history, state, matches, submission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, fetchLoadMatches, routesToUse, basename, pendingActionData, pendingError) {
|
|
3444
3555
|
let actionResult = pendingError ? Object.values(pendingError)[0] : pendingActionData ? Object.values(pendingActionData)[0] : undefined;
|
|
3445
3556
|
let currentUrl = history.createURL(state.location);
|
|
3446
|
-
let nextUrl = history.createURL(location);
|
|
3447
|
-
let defaultShouldRevalidate = // Forced revalidation due to submission, useRevalidate, or X-Remix-Revalidate
|
|
3448
|
-
isRevalidationRequired || // Clicked the same link, resubmitted a GET form
|
|
3449
|
-
currentUrl.toString() === nextUrl.toString() || // Search params affect all loaders
|
|
3450
|
-
currentUrl.search !== nextUrl.search; // Pick navigation matches that are net-new or qualify for revalidation
|
|
3557
|
+
let nextUrl = history.createURL(location); // Pick navigation matches that are net-new or qualify for revalidation
|
|
3451
3558
|
|
|
3452
3559
|
let boundaryId = pendingError ? Object.keys(pendingError)[0] : undefined;
|
|
3453
3560
|
let boundaryMatches = getLoaderMatchesUntilBoundary(matches, boundaryId);
|
|
@@ -3479,7 +3586,10 @@ function getMatchesToLoad(history, state, matches, submission, location, isReval
|
|
|
3479
3586
|
nextParams: nextRouteMatch.params
|
|
3480
3587
|
}, submission, {
|
|
3481
3588
|
actionResult,
|
|
3482
|
-
defaultShouldRevalidate:
|
|
3589
|
+
defaultShouldRevalidate: // Forced revalidation due to submission, useRevalidator, or X-Remix-Revalidate
|
|
3590
|
+
isRevalidationRequired || // Clicked the same link, resubmitted a GET form
|
|
3591
|
+
currentUrl.toString() === nextUrl.toString() || // Search params affect all loaders
|
|
3592
|
+
currentUrl.search !== nextUrl.search || isNewRouteInstance(currentRouteMatch, nextRouteMatch)
|
|
3483
3593
|
}));
|
|
3484
3594
|
}); // Pick fetcher.loads that need to be revalidated
|
|
3485
3595
|
|
|
@@ -3494,23 +3604,28 @@ function getMatchesToLoad(history, state, matches, submission, location, isReval
|
|
|
3494
3604
|
// we can trigger a 404 in callLoadersAndMaybeResolveData
|
|
3495
3605
|
|
|
3496
3606
|
if (!fetcherMatches) {
|
|
3497
|
-
revalidatingFetchers.push(
|
|
3498
|
-
key
|
|
3499
|
-
|
|
3607
|
+
revalidatingFetchers.push({
|
|
3608
|
+
key,
|
|
3609
|
+
routeId: f.routeId,
|
|
3610
|
+
path: f.path,
|
|
3500
3611
|
matches: null,
|
|
3501
|
-
match: null
|
|
3502
|
-
|
|
3612
|
+
match: null,
|
|
3613
|
+
controller: null
|
|
3614
|
+
});
|
|
3503
3615
|
return;
|
|
3504
3616
|
}
|
|
3505
3617
|
|
|
3506
3618
|
let fetcherMatch = getTargetMatch(fetcherMatches, f.path);
|
|
3507
3619
|
|
|
3508
3620
|
if (cancelledFetcherLoads.includes(key)) {
|
|
3509
|
-
revalidatingFetchers.push(
|
|
3621
|
+
revalidatingFetchers.push({
|
|
3510
3622
|
key,
|
|
3623
|
+
routeId: f.routeId,
|
|
3624
|
+
path: f.path,
|
|
3511
3625
|
matches: fetcherMatches,
|
|
3512
|
-
match: fetcherMatch
|
|
3513
|
-
|
|
3626
|
+
match: fetcherMatch,
|
|
3627
|
+
controller: new AbortController()
|
|
3628
|
+
});
|
|
3514
3629
|
return;
|
|
3515
3630
|
} // Revalidating fetchers are decoupled from the route matches since they
|
|
3516
3631
|
// hit a static href, so they _always_ check shouldRevalidate and the
|
|
@@ -3525,15 +3640,19 @@ function getMatchesToLoad(history, state, matches, submission, location, isReval
|
|
|
3525
3640
|
nextParams: matches[matches.length - 1].params
|
|
3526
3641
|
}, submission, {
|
|
3527
3642
|
actionResult,
|
|
3528
|
-
|
|
3643
|
+
// Forced revalidation due to submission, useRevalidator, or X-Remix-Revalidate
|
|
3644
|
+
defaultShouldRevalidate: isRevalidationRequired
|
|
3529
3645
|
}));
|
|
3530
3646
|
|
|
3531
3647
|
if (shouldRevalidate) {
|
|
3532
|
-
revalidatingFetchers.push(
|
|
3648
|
+
revalidatingFetchers.push({
|
|
3533
3649
|
key,
|
|
3650
|
+
routeId: f.routeId,
|
|
3651
|
+
path: f.path,
|
|
3534
3652
|
matches: fetcherMatches,
|
|
3535
|
-
match: fetcherMatch
|
|
3536
|
-
|
|
3653
|
+
match: fetcherMatch,
|
|
3654
|
+
controller: new AbortController()
|
|
3655
|
+
});
|
|
3537
3656
|
}
|
|
3538
3657
|
});
|
|
3539
3658
|
return [navigationMatches, revalidatingFetchers];
|
|
@@ -3577,7 +3696,7 @@ function shouldRevalidateLoader(loaderMatch, arg) {
|
|
|
3577
3696
|
*/
|
|
3578
3697
|
|
|
3579
3698
|
|
|
3580
|
-
async function loadLazyRouteModule(route,
|
|
3699
|
+
async function loadLazyRouteModule(route, mapRouteProperties, manifest) {
|
|
3581
3700
|
if (!route.lazy) {
|
|
3582
3701
|
return;
|
|
3583
3702
|
}
|
|
@@ -3613,27 +3732,19 @@ async function loadLazyRouteModule(route, detectErrorBoundary, manifest) {
|
|
|
3613
3732
|
routeUpdates[lazyRouteProperty] = lazyRoute[lazyRouteProperty];
|
|
3614
3733
|
}
|
|
3615
3734
|
} // Mutate the route with the provided updates. Do this first so we pass
|
|
3616
|
-
// the updated version to
|
|
3735
|
+
// the updated version to mapRouteProperties
|
|
3617
3736
|
|
|
3618
3737
|
|
|
3619
3738
|
Object.assign(routeToUpdate, routeUpdates); // Mutate the `hasErrorBoundary` property on the route based on the route
|
|
3620
3739
|
// updates and remove the `lazy` function so we don't resolve the lazy
|
|
3621
3740
|
// route again.
|
|
3622
3741
|
|
|
3623
|
-
Object.assign(routeToUpdate, {
|
|
3624
|
-
// To keep things framework agnostic, we use the provided
|
|
3625
|
-
// `detectErrorBoundary` function to set the `hasErrorBoundary` route
|
|
3626
|
-
// property since the logic will differ between frameworks.
|
|
3627
|
-
hasErrorBoundary: detectErrorBoundary(_extends({}, routeToUpdate)),
|
|
3742
|
+
Object.assign(routeToUpdate, _extends({}, mapRouteProperties(routeToUpdate), {
|
|
3628
3743
|
lazy: undefined
|
|
3629
|
-
});
|
|
3744
|
+
}));
|
|
3630
3745
|
}
|
|
3631
3746
|
|
|
3632
|
-
async function callLoaderOrAction(type, request, match, matches, manifest,
|
|
3633
|
-
if (basename === void 0) {
|
|
3634
|
-
basename = "/";
|
|
3635
|
-
}
|
|
3636
|
-
|
|
3747
|
+
async function callLoaderOrAction(type, request, match, matches, manifest, mapRouteProperties, basename, isStaticRequest, isRouteRequest, requestContext) {
|
|
3637
3748
|
if (isStaticRequest === void 0) {
|
|
3638
3749
|
isStaticRequest = false;
|
|
3639
3750
|
}
|
|
@@ -3667,11 +3778,11 @@ async function callLoaderOrAction(type, request, match, matches, manifest, detec
|
|
|
3667
3778
|
if (match.route.lazy) {
|
|
3668
3779
|
if (handler) {
|
|
3669
3780
|
// Run statically defined handler in parallel with lazy()
|
|
3670
|
-
let values = await Promise.all([runHandler(handler), loadLazyRouteModule(match.route,
|
|
3781
|
+
let values = await Promise.all([runHandler(handler), loadLazyRouteModule(match.route, mapRouteProperties, manifest)]);
|
|
3671
3782
|
result = values[0];
|
|
3672
3783
|
} else {
|
|
3673
3784
|
// Load lazy route module, then run any returned handler
|
|
3674
|
-
await loadLazyRouteModule(match.route,
|
|
3785
|
+
await loadLazyRouteModule(match.route, mapRouteProperties, manifest);
|
|
3675
3786
|
handler = match.route[type];
|
|
3676
3787
|
|
|
3677
3788
|
if (handler) {
|
|
@@ -3680,9 +3791,11 @@ async function callLoaderOrAction(type, request, match, matches, manifest, detec
|
|
|
3680
3791
|
// previously-lazy-loaded routes
|
|
3681
3792
|
result = await runHandler(handler);
|
|
3682
3793
|
} else if (type === "action") {
|
|
3794
|
+
let url = new URL(request.url);
|
|
3795
|
+
let pathname = url.pathname + url.search;
|
|
3683
3796
|
throw getInternalRouterError(405, {
|
|
3684
3797
|
method: request.method,
|
|
3685
|
-
pathname
|
|
3798
|
+
pathname,
|
|
3686
3799
|
routeId: match.route.id
|
|
3687
3800
|
});
|
|
3688
3801
|
} else {
|
|
@@ -3694,8 +3807,13 @@ async function callLoaderOrAction(type, request, match, matches, manifest, detec
|
|
|
3694
3807
|
};
|
|
3695
3808
|
}
|
|
3696
3809
|
}
|
|
3810
|
+
} else if (!handler) {
|
|
3811
|
+
let url = new URL(request.url);
|
|
3812
|
+
let pathname = url.pathname + url.search;
|
|
3813
|
+
throw getInternalRouterError(404, {
|
|
3814
|
+
pathname
|
|
3815
|
+
});
|
|
3697
3816
|
} else {
|
|
3698
|
-
invariant(handler, "Could not find the " + type + " to run on the \"" + match.route.id + "\" route");
|
|
3699
3817
|
result = await runHandler(handler);
|
|
3700
3818
|
}
|
|
3701
3819
|
|
|
@@ -3717,17 +3835,7 @@ async function callLoaderOrAction(type, request, match, matches, manifest, detec
|
|
|
3717
3835
|
invariant(location, "Redirects returned/thrown from loaders/actions must have a Location header"); // Support relative routing in internal redirects
|
|
3718
3836
|
|
|
3719
3837
|
if (!ABSOLUTE_URL_REGEX.test(location)) {
|
|
3720
|
-
|
|
3721
|
-
let routePathnames = getPathContributingMatches(activeMatches).map(match => match.pathnameBase);
|
|
3722
|
-
let resolvedLocation = resolveTo(location, routePathnames, new URL(request.url).pathname);
|
|
3723
|
-
invariant(createPath(resolvedLocation), "Unable to resolve redirect location: " + location); // Prepend the basename to the redirect location if we have one
|
|
3724
|
-
|
|
3725
|
-
if (basename) {
|
|
3726
|
-
let path = resolvedLocation.pathname;
|
|
3727
|
-
resolvedLocation.pathname = path === "/" ? basename : joinPaths([basename, path]);
|
|
3728
|
-
}
|
|
3729
|
-
|
|
3730
|
-
location = createPath(resolvedLocation);
|
|
3838
|
+
location = normalizeTo(new URL(request.url), matches.slice(0, matches.indexOf(match) + 1), basename, true, location);
|
|
3731
3839
|
} else if (!isStaticRequest) {
|
|
3732
3840
|
// Strip off the protocol+origin for same-origin + same-basename absolute
|
|
3733
3841
|
// redirects. If this is a static request, we can let it go back to the
|
|
@@ -3943,12 +4051,16 @@ function processLoaderData(state, matches, matchesToLoad, results, pendingError,
|
|
|
3943
4051
|
for (let index = 0; index < revalidatingFetchers.length; index++) {
|
|
3944
4052
|
let {
|
|
3945
4053
|
key,
|
|
3946
|
-
match
|
|
4054
|
+
match,
|
|
4055
|
+
controller
|
|
3947
4056
|
} = revalidatingFetchers[index];
|
|
3948
4057
|
invariant(fetcherResults !== undefined && fetcherResults[index] !== undefined, "Did not find corresponding fetcher result");
|
|
3949
4058
|
let result = fetcherResults[index]; // Process fetcher non-redirect errors
|
|
3950
4059
|
|
|
3951
|
-
if (
|
|
4060
|
+
if (controller && controller.signal.aborted) {
|
|
4061
|
+
// Nothing to do for aborted fetchers
|
|
4062
|
+
continue;
|
|
4063
|
+
} else if (isErrorResult(result)) {
|
|
3952
4064
|
let boundaryMatch = findNearestBoundary(state.matches, match == null ? void 0 : match.route.id);
|
|
3953
4065
|
|
|
3954
4066
|
if (!(errors && errors[boundaryMatch.route.id])) {
|
|
@@ -4137,7 +4249,7 @@ function isMutationMethod(method) {
|
|
|
4137
4249
|
return validMutationMethods.has(method.toLowerCase());
|
|
4138
4250
|
}
|
|
4139
4251
|
|
|
4140
|
-
async function resolveDeferredResults(currentMatches, matchesToLoad, results,
|
|
4252
|
+
async function resolveDeferredResults(currentMatches, matchesToLoad, results, signals, isFetcher, currentLoaderData) {
|
|
4141
4253
|
for (let index = 0; index < results.length; index++) {
|
|
4142
4254
|
let result = results[index];
|
|
4143
4255
|
let match = matchesToLoad[index]; // If we don't have a match, then we can have a deferred result to do
|
|
@@ -4155,6 +4267,8 @@ async function resolveDeferredResults(currentMatches, matchesToLoad, results, si
|
|
|
4155
4267
|
// Note: we do not have to touch activeDeferreds here since we race them
|
|
4156
4268
|
// against the signal in resolveDeferredData and they'll get aborted
|
|
4157
4269
|
// there if needed
|
|
4270
|
+
let signal = signals[index];
|
|
4271
|
+
invariant(signal, "Expected an AbortSignal for revalidating fetcher deferred result");
|
|
4158
4272
|
await resolveDeferredData(result, signal, isFetcher).then(result => {
|
|
4159
4273
|
if (result) {
|
|
4160
4274
|
results[index] = result || results[index];
|