@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.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
|
*
|
|
@@ -534,7 +534,7 @@ function isIndexRoute(route) {
|
|
|
534
534
|
// solely with AgnosticDataRouteObject's within the Router
|
|
535
535
|
|
|
536
536
|
|
|
537
|
-
function convertRoutesToDataRoutes(routes,
|
|
537
|
+
function convertRoutesToDataRoutes(routes, mapRouteProperties, parentPath, manifest) {
|
|
538
538
|
if (parentPath === void 0) {
|
|
539
539
|
parentPath = [];
|
|
540
540
|
}
|
|
@@ -550,24 +550,22 @@ function convertRoutesToDataRoutes(routes, detectErrorBoundary, parentPath, mani
|
|
|
550
550
|
invariant(!manifest[id], "Found a route id collision on id \"" + id + "\". Route " + "id's must be globally unique within Data Router usages");
|
|
551
551
|
|
|
552
552
|
if (isIndexRoute(route)) {
|
|
553
|
-
let indexRoute = _extends({}, route, {
|
|
554
|
-
hasErrorBoundary: detectErrorBoundary(route),
|
|
553
|
+
let indexRoute = _extends({}, route, mapRouteProperties(route), {
|
|
555
554
|
id
|
|
556
555
|
});
|
|
557
556
|
|
|
558
557
|
manifest[id] = indexRoute;
|
|
559
558
|
return indexRoute;
|
|
560
559
|
} else {
|
|
561
|
-
let pathOrLayoutRoute = _extends({}, route, {
|
|
560
|
+
let pathOrLayoutRoute = _extends({}, route, mapRouteProperties(route), {
|
|
562
561
|
id,
|
|
563
|
-
hasErrorBoundary: detectErrorBoundary(route),
|
|
564
562
|
children: undefined
|
|
565
563
|
});
|
|
566
564
|
|
|
567
565
|
manifest[id] = pathOrLayoutRoute;
|
|
568
566
|
|
|
569
567
|
if (route.children) {
|
|
570
|
-
pathOrLayoutRoute.children = convertRoutesToDataRoutes(route.children,
|
|
568
|
+
pathOrLayoutRoute.children = convertRoutesToDataRoutes(route.children, mapRouteProperties, treePath, manifest);
|
|
571
569
|
}
|
|
572
570
|
|
|
573
571
|
return pathOrLayoutRoute;
|
|
@@ -1419,7 +1417,9 @@ const ABSOLUTE_URL_REGEX = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;
|
|
|
1419
1417
|
const isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined";
|
|
1420
1418
|
const isServer = !isBrowser;
|
|
1421
1419
|
|
|
1422
|
-
const
|
|
1420
|
+
const defaultMapRouteProperties = route => ({
|
|
1421
|
+
hasErrorBoundary: Boolean(route.hasErrorBoundary)
|
|
1422
|
+
}); //#endregion
|
|
1423
1423
|
////////////////////////////////////////////////////////////////////////////////
|
|
1424
1424
|
//#region createRouter
|
|
1425
1425
|
////////////////////////////////////////////////////////////////////////////////
|
|
@@ -1431,15 +1431,31 @@ const defaultDetectErrorBoundary = route => Boolean(route.hasErrorBoundary); //#
|
|
|
1431
1431
|
|
|
1432
1432
|
function createRouter(init) {
|
|
1433
1433
|
invariant(init.routes.length > 0, "You must provide a non-empty routes array to createRouter");
|
|
1434
|
-
let
|
|
1434
|
+
let mapRouteProperties;
|
|
1435
|
+
|
|
1436
|
+
if (init.mapRouteProperties) {
|
|
1437
|
+
mapRouteProperties = init.mapRouteProperties;
|
|
1438
|
+
} else if (init.detectErrorBoundary) {
|
|
1439
|
+
// If they are still using the deprecated version, wrap it with the new API
|
|
1440
|
+
let detectErrorBoundary = init.detectErrorBoundary;
|
|
1441
|
+
|
|
1442
|
+
mapRouteProperties = route => ({
|
|
1443
|
+
hasErrorBoundary: detectErrorBoundary(route)
|
|
1444
|
+
});
|
|
1445
|
+
} else {
|
|
1446
|
+
mapRouteProperties = defaultMapRouteProperties;
|
|
1447
|
+
} // Routes keyed by ID
|
|
1448
|
+
|
|
1435
1449
|
|
|
1436
1450
|
let manifest = {}; // Routes in tree format for matching
|
|
1437
1451
|
|
|
1438
|
-
let dataRoutes = convertRoutesToDataRoutes(init.routes,
|
|
1439
|
-
let inFlightDataRoutes;
|
|
1452
|
+
let dataRoutes = convertRoutesToDataRoutes(init.routes, mapRouteProperties, undefined, manifest);
|
|
1453
|
+
let inFlightDataRoutes;
|
|
1454
|
+
let basename = init.basename || "/"; // Config driven behavior flags
|
|
1440
1455
|
|
|
1441
1456
|
let future = _extends({
|
|
1442
|
-
v7_normalizeFormMethod: false
|
|
1457
|
+
v7_normalizeFormMethod: false,
|
|
1458
|
+
v7_prependBasename: false
|
|
1443
1459
|
}, init.future); // Cleanup function for history
|
|
1444
1460
|
|
|
1445
1461
|
|
|
@@ -1459,7 +1475,7 @@ function createRouter(init) {
|
|
|
1459
1475
|
// SSR did the initial scroll restoration.
|
|
1460
1476
|
|
|
1461
1477
|
let initialScrollRestored = init.hydrationData != null;
|
|
1462
|
-
let initialMatches = matchRoutes(dataRoutes, init.history.location,
|
|
1478
|
+
let initialMatches = matchRoutes(dataRoutes, init.history.location, basename);
|
|
1463
1479
|
let initialErrors = null;
|
|
1464
1480
|
|
|
1465
1481
|
if (initialMatches == null) {
|
|
@@ -1511,7 +1527,7 @@ function createRouter(init) {
|
|
|
1511
1527
|
|
|
1512
1528
|
let isUninterruptedRevalidation = false; // Use this internal flag to force revalidation of all loaders:
|
|
1513
1529
|
// - submissions (completed or interrupted)
|
|
1514
|
-
// -
|
|
1530
|
+
// - useRevalidator()
|
|
1515
1531
|
// - X-Remix-Revalidate (from redirect)
|
|
1516
1532
|
|
|
1517
1533
|
let isRevalidationRequired = false; // Use this internal array to capture routes that require revalidation due
|
|
@@ -1530,7 +1546,7 @@ function createRouter(init) {
|
|
|
1530
1546
|
|
|
1531
1547
|
let pendingNavigationLoadId = -1; // Fetchers that triggered data reloads as a result of their actions
|
|
1532
1548
|
|
|
1533
|
-
let fetchReloadIds = new Map(); // Fetchers that triggered redirect navigations
|
|
1549
|
+
let fetchReloadIds = new Map(); // Fetchers that triggered redirect navigations
|
|
1534
1550
|
|
|
1535
1551
|
let fetchRedirectIds = new Set(); // Most recent href/match for fetcher.load calls for fetchers
|
|
1536
1552
|
|
|
@@ -1726,11 +1742,12 @@ function createRouter(init) {
|
|
|
1726
1742
|
return;
|
|
1727
1743
|
}
|
|
1728
1744
|
|
|
1745
|
+
let normalizedPath = normalizeTo(state.location, state.matches, basename, future.v7_prependBasename, to, opts == null ? void 0 : opts.fromRouteId, opts == null ? void 0 : opts.relative);
|
|
1729
1746
|
let {
|
|
1730
1747
|
path,
|
|
1731
1748
|
submission,
|
|
1732
1749
|
error
|
|
1733
|
-
} = normalizeNavigateOptions(
|
|
1750
|
+
} = normalizeNavigateOptions(future.v7_normalizeFormMethod, false, normalizedPath, opts);
|
|
1734
1751
|
let currentLocation = state.location;
|
|
1735
1752
|
let nextLocation = createLocation(state.location, path, opts && opts.state); // When using navigate as a PUSH/REPLACE we aren't reading an already-encoded
|
|
1736
1753
|
// URL from window.location, so we need to encode it here so the behavior
|
|
@@ -1846,7 +1863,7 @@ function createRouter(init) {
|
|
|
1846
1863
|
pendingPreventScrollReset = (opts && opts.preventScrollReset) === true;
|
|
1847
1864
|
let routesToUse = inFlightDataRoutes || dataRoutes;
|
|
1848
1865
|
let loadingNavigation = opts && opts.overrideNavigation;
|
|
1849
|
-
let matches = matchRoutes(routesToUse, location,
|
|
1866
|
+
let matches = matchRoutes(routesToUse, location, basename); // Short circuit with a 404 on the root error boundary if we match nothing
|
|
1850
1867
|
|
|
1851
1868
|
if (!matches) {
|
|
1852
1869
|
let error = getInternalRouterError(404, {
|
|
@@ -1969,7 +1986,7 @@ function createRouter(init) {
|
|
|
1969
1986
|
})
|
|
1970
1987
|
};
|
|
1971
1988
|
} else {
|
|
1972
|
-
result = await callLoaderOrAction("action", request, actionMatch, matches, manifest,
|
|
1989
|
+
result = await callLoaderOrAction("action", request, actionMatch, matches, manifest, mapRouteProperties, basename);
|
|
1973
1990
|
|
|
1974
1991
|
if (request.signal.aborted) {
|
|
1975
1992
|
return {
|
|
@@ -2061,13 +2078,14 @@ function createRouter(init) {
|
|
|
2061
2078
|
formEncType: loadingNavigation.formEncType
|
|
2062
2079
|
} : undefined;
|
|
2063
2080
|
let routesToUse = inFlightDataRoutes || dataRoutes;
|
|
2064
|
-
let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, activeSubmission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, fetchLoadMatches, routesToUse,
|
|
2081
|
+
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
|
|
2065
2082
|
// about to reload. Note that if this is an action reload we would have
|
|
2066
2083
|
// already cancelled all pending deferreds so this would be a no-op
|
|
2067
2084
|
|
|
2068
2085
|
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
|
|
2069
2086
|
|
|
2070
2087
|
if (matchesToLoad.length === 0 && revalidatingFetchers.length === 0) {
|
|
2088
|
+
let updatedFetchers = markFetchRedirectsDone();
|
|
2071
2089
|
completeNavigation(location, _extends({
|
|
2072
2090
|
matches,
|
|
2073
2091
|
loaderData: {},
|
|
@@ -2075,6 +2093,8 @@ function createRouter(init) {
|
|
|
2075
2093
|
errors: pendingError || null
|
|
2076
2094
|
}, pendingActionData ? {
|
|
2077
2095
|
actionData: pendingActionData
|
|
2096
|
+
} : {}, updatedFetchers ? {
|
|
2097
|
+
fetchers: new Map(state.fetchers)
|
|
2078
2098
|
} : {}));
|
|
2079
2099
|
return {
|
|
2080
2100
|
shortCircuited: true
|
|
@@ -2112,7 +2132,21 @@ function createRouter(init) {
|
|
|
2112
2132
|
}
|
|
2113
2133
|
|
|
2114
2134
|
pendingNavigationLoadId = ++incrementingLoadId;
|
|
2115
|
-
revalidatingFetchers.forEach(rf =>
|
|
2135
|
+
revalidatingFetchers.forEach(rf => {
|
|
2136
|
+
if (rf.controller) {
|
|
2137
|
+
// Fetchers use an independent AbortController so that aborting a fetcher
|
|
2138
|
+
// (via deleteFetcher) does not abort the triggering navigation that
|
|
2139
|
+
// triggered the revalidation
|
|
2140
|
+
fetchControllers.set(rf.key, rf.controller);
|
|
2141
|
+
}
|
|
2142
|
+
}); // Proxy navigation abort through to revalidation fetchers
|
|
2143
|
+
|
|
2144
|
+
let abortPendingFetchRevalidations = () => revalidatingFetchers.forEach(f => abortFetcher(f.key));
|
|
2145
|
+
|
|
2146
|
+
if (pendingNavigationController) {
|
|
2147
|
+
pendingNavigationController.signal.addEventListener("abort", abortPendingFetchRevalidations);
|
|
2148
|
+
}
|
|
2149
|
+
|
|
2116
2150
|
let {
|
|
2117
2151
|
results,
|
|
2118
2152
|
loaderResults,
|
|
@@ -2128,6 +2162,10 @@ function createRouter(init) {
|
|
|
2128
2162
|
// reassigned to new controllers for the next navigation
|
|
2129
2163
|
|
|
2130
2164
|
|
|
2165
|
+
if (pendingNavigationController) {
|
|
2166
|
+
pendingNavigationController.signal.removeEventListener("abort", abortPendingFetchRevalidations);
|
|
2167
|
+
}
|
|
2168
|
+
|
|
2131
2169
|
revalidatingFetchers.forEach(rf => fetchControllers.delete(rf.key)); // If any loaders returned a redirect Response, start a new REPLACE navigation
|
|
2132
2170
|
|
|
2133
2171
|
let redirect = findRedirect(results);
|
|
@@ -2157,12 +2195,13 @@ function createRouter(init) {
|
|
|
2157
2195
|
}
|
|
2158
2196
|
});
|
|
2159
2197
|
});
|
|
2160
|
-
markFetchRedirectsDone();
|
|
2198
|
+
let updatedFetchers = markFetchRedirectsDone();
|
|
2161
2199
|
let didAbortFetchLoads = abortStaleFetchLoads(pendingNavigationLoadId);
|
|
2200
|
+
let shouldUpdateFetchers = updatedFetchers || didAbortFetchLoads || revalidatingFetchers.length > 0;
|
|
2162
2201
|
return _extends({
|
|
2163
2202
|
loaderData,
|
|
2164
2203
|
errors
|
|
2165
|
-
},
|
|
2204
|
+
}, shouldUpdateFetchers ? {
|
|
2166
2205
|
fetchers: new Map(state.fetchers)
|
|
2167
2206
|
} : {});
|
|
2168
2207
|
}
|
|
@@ -2179,11 +2218,12 @@ function createRouter(init) {
|
|
|
2179
2218
|
|
|
2180
2219
|
if (fetchControllers.has(key)) abortFetcher(key);
|
|
2181
2220
|
let routesToUse = inFlightDataRoutes || dataRoutes;
|
|
2182
|
-
let
|
|
2221
|
+
let normalizedPath = normalizeTo(state.location, state.matches, basename, future.v7_prependBasename, href, routeId, opts == null ? void 0 : opts.relative);
|
|
2222
|
+
let matches = matchRoutes(routesToUse, normalizedPath, basename);
|
|
2183
2223
|
|
|
2184
2224
|
if (!matches) {
|
|
2185
2225
|
setFetcherError(key, routeId, getInternalRouterError(404, {
|
|
2186
|
-
pathname:
|
|
2226
|
+
pathname: normalizedPath
|
|
2187
2227
|
}));
|
|
2188
2228
|
return;
|
|
2189
2229
|
}
|
|
@@ -2191,7 +2231,7 @@ function createRouter(init) {
|
|
|
2191
2231
|
let {
|
|
2192
2232
|
path,
|
|
2193
2233
|
submission
|
|
2194
|
-
} = normalizeNavigateOptions(
|
|
2234
|
+
} = normalizeNavigateOptions(future.v7_normalizeFormMethod, true, normalizedPath, opts);
|
|
2195
2235
|
let match = getTargetMatch(matches, path);
|
|
2196
2236
|
pendingPreventScrollReset = (opts && opts.preventScrollReset) === true;
|
|
2197
2237
|
|
|
@@ -2243,7 +2283,7 @@ function createRouter(init) {
|
|
|
2243
2283
|
let abortController = new AbortController();
|
|
2244
2284
|
let fetchRequest = createClientSideRequest(init.history, path, abortController.signal, submission);
|
|
2245
2285
|
fetchControllers.set(key, abortController);
|
|
2246
|
-
let actionResult = await callLoaderOrAction("action", fetchRequest, match, requestMatches, manifest,
|
|
2286
|
+
let actionResult = await callLoaderOrAction("action", fetchRequest, match, requestMatches, manifest, mapRouteProperties, basename);
|
|
2247
2287
|
|
|
2248
2288
|
if (fetchRequest.signal.aborted) {
|
|
2249
2289
|
// We can delete this so long as we weren't aborted by ou our own fetcher
|
|
@@ -2293,7 +2333,7 @@ function createRouter(init) {
|
|
|
2293
2333
|
let nextLocation = state.navigation.location || state.location;
|
|
2294
2334
|
let revalidationRequest = createClientSideRequest(init.history, nextLocation, abortController.signal);
|
|
2295
2335
|
let routesToUse = inFlightDataRoutes || dataRoutes;
|
|
2296
|
-
let matches = state.navigation.state !== "idle" ? matchRoutes(routesToUse, state.navigation.location,
|
|
2336
|
+
let matches = state.navigation.state !== "idle" ? matchRoutes(routesToUse, state.navigation.location, basename) : state.matches;
|
|
2297
2337
|
invariant(matches, "Didn't find any matches after fetcher action");
|
|
2298
2338
|
let loadId = ++incrementingLoadId;
|
|
2299
2339
|
fetchReloadIds.set(key, loadId);
|
|
@@ -2306,7 +2346,7 @@ function createRouter(init) {
|
|
|
2306
2346
|
});
|
|
2307
2347
|
|
|
2308
2348
|
state.fetchers.set(key, loadFetcher);
|
|
2309
|
-
let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, submission, nextLocation, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, fetchLoadMatches, routesToUse,
|
|
2349
|
+
let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, submission, nextLocation, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, fetchLoadMatches, routesToUse, basename, {
|
|
2310
2350
|
[match.route.id]: actionResult.data
|
|
2311
2351
|
}, undefined // No need to send through errors since we short circuit above
|
|
2312
2352
|
); // Put all revalidating fetchers into the loading state, except for the
|
|
@@ -2326,11 +2366,18 @@ function createRouter(init) {
|
|
|
2326
2366
|
" _hasFetcherDoneAnything ": true
|
|
2327
2367
|
};
|
|
2328
2368
|
state.fetchers.set(staleKey, revalidatingFetcher);
|
|
2329
|
-
|
|
2369
|
+
|
|
2370
|
+
if (rf.controller) {
|
|
2371
|
+
fetchControllers.set(staleKey, rf.controller);
|
|
2372
|
+
}
|
|
2330
2373
|
});
|
|
2331
2374
|
updateState({
|
|
2332
2375
|
fetchers: new Map(state.fetchers)
|
|
2333
2376
|
});
|
|
2377
|
+
|
|
2378
|
+
let abortPendingFetchRevalidations = () => revalidatingFetchers.forEach(rf => abortFetcher(rf.key));
|
|
2379
|
+
|
|
2380
|
+
abortController.signal.addEventListener("abort", abortPendingFetchRevalidations);
|
|
2334
2381
|
let {
|
|
2335
2382
|
results,
|
|
2336
2383
|
loaderResults,
|
|
@@ -2341,6 +2388,7 @@ function createRouter(init) {
|
|
|
2341
2388
|
return;
|
|
2342
2389
|
}
|
|
2343
2390
|
|
|
2391
|
+
abortController.signal.removeEventListener("abort", abortPendingFetchRevalidations);
|
|
2344
2392
|
fetchReloadIds.delete(key);
|
|
2345
2393
|
fetchControllers.delete(key);
|
|
2346
2394
|
revalidatingFetchers.forEach(r => fetchControllers.delete(r.key));
|
|
@@ -2415,14 +2463,14 @@ function createRouter(init) {
|
|
|
2415
2463
|
let abortController = new AbortController();
|
|
2416
2464
|
let fetchRequest = createClientSideRequest(init.history, path, abortController.signal);
|
|
2417
2465
|
fetchControllers.set(key, abortController);
|
|
2418
|
-
let result = await callLoaderOrAction("loader", fetchRequest, match, matches, manifest,
|
|
2466
|
+
let result = await callLoaderOrAction("loader", fetchRequest, match, matches, manifest, mapRouteProperties, basename); // Deferred isn't supported for fetcher loads, await everything and treat it
|
|
2419
2467
|
// as a normal load. resolveDeferredData will return undefined if this
|
|
2420
2468
|
// fetcher gets aborted, so we just leave result untouched and short circuit
|
|
2421
2469
|
// below if that happens
|
|
2422
2470
|
|
|
2423
2471
|
if (isDeferredResult(result)) {
|
|
2424
2472
|
result = (await resolveDeferredData(result, fetchRequest.signal, true)) || result;
|
|
2425
|
-
} // We can delete this so long as we weren't aborted by
|
|
2473
|
+
} // We can delete this so long as we weren't aborted by our our own fetcher
|
|
2426
2474
|
// re-load which would have put _new_ controller is in fetchControllers
|
|
2427
2475
|
|
|
2428
2476
|
|
|
@@ -2436,6 +2484,7 @@ function createRouter(init) {
|
|
|
2436
2484
|
|
|
2437
2485
|
|
|
2438
2486
|
if (isRedirectResult(result)) {
|
|
2487
|
+
fetchRedirectIds.add(key);
|
|
2439
2488
|
await startRedirectNavigation(state, result);
|
|
2440
2489
|
return;
|
|
2441
2490
|
} // Process any non-redirect errors thrown
|
|
@@ -2516,7 +2565,7 @@ function createRouter(init) {
|
|
|
2516
2565
|
|
|
2517
2566
|
if (ABSOLUTE_URL_REGEX.test(redirect.location) && isBrowser && typeof ((_window = window) == null ? void 0 : _window.location) !== "undefined") {
|
|
2518
2567
|
let url = init.history.createURL(redirect.location);
|
|
2519
|
-
let isDifferentBasename = stripBasename(url.pathname,
|
|
2568
|
+
let isDifferentBasename = stripBasename(url.pathname, basename) == null;
|
|
2520
2569
|
|
|
2521
2570
|
if (window.location.origin !== url.origin || isDifferentBasename) {
|
|
2522
2571
|
if (replace) {
|
|
@@ -2600,9 +2649,9 @@ function createRouter(init) {
|
|
|
2600
2649
|
// Call all navigation loaders and revalidating fetcher loaders in parallel,
|
|
2601
2650
|
// then slice off the results into separate arrays so we can handle them
|
|
2602
2651
|
// accordingly
|
|
2603
|
-
let results = await Promise.all([...matchesToLoad.map(match => callLoaderOrAction("loader", request, match, matches, manifest,
|
|
2604
|
-
if (f.matches && f.match) {
|
|
2605
|
-
return callLoaderOrAction("loader", createClientSideRequest(init.history, f.path,
|
|
2652
|
+
let results = await Promise.all([...matchesToLoad.map(match => callLoaderOrAction("loader", request, match, matches, manifest, mapRouteProperties, basename)), ...fetchersToLoad.map(f => {
|
|
2653
|
+
if (f.matches && f.match && f.controller) {
|
|
2654
|
+
return callLoaderOrAction("loader", createClientSideRequest(init.history, f.path, f.controller.signal), f.match, f.matches, manifest, mapRouteProperties, basename);
|
|
2606
2655
|
} else {
|
|
2607
2656
|
let error = {
|
|
2608
2657
|
type: ResultType.error,
|
|
@@ -2615,7 +2664,7 @@ function createRouter(init) {
|
|
|
2615
2664
|
})]);
|
|
2616
2665
|
let loaderResults = results.slice(0, matchesToLoad.length);
|
|
2617
2666
|
let fetcherResults = results.slice(matchesToLoad.length);
|
|
2618
|
-
await Promise.all([resolveDeferredResults(currentMatches, matchesToLoad, loaderResults, request.signal, false, state.loaderData), resolveDeferredResults(currentMatches, fetchersToLoad.map(f => f.match), fetcherResults,
|
|
2667
|
+
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)]);
|
|
2619
2668
|
return {
|
|
2620
2669
|
results,
|
|
2621
2670
|
loaderResults,
|
|
@@ -2682,6 +2731,7 @@ function createRouter(init) {
|
|
|
2682
2731
|
|
|
2683
2732
|
function markFetchRedirectsDone() {
|
|
2684
2733
|
let doneKeys = [];
|
|
2734
|
+
let updatedFetchers = false;
|
|
2685
2735
|
|
|
2686
2736
|
for (let key of fetchRedirectIds) {
|
|
2687
2737
|
let fetcher = state.fetchers.get(key);
|
|
@@ -2690,10 +2740,12 @@ function createRouter(init) {
|
|
|
2690
2740
|
if (fetcher.state === "loading") {
|
|
2691
2741
|
fetchRedirectIds.delete(key);
|
|
2692
2742
|
doneKeys.push(key);
|
|
2743
|
+
updatedFetchers = true;
|
|
2693
2744
|
}
|
|
2694
2745
|
}
|
|
2695
2746
|
|
|
2696
2747
|
markFetchersDone(doneKeys);
|
|
2748
|
+
return updatedFetchers;
|
|
2697
2749
|
}
|
|
2698
2750
|
|
|
2699
2751
|
function abortStaleFetchLoads(landedId) {
|
|
@@ -2853,7 +2905,7 @@ function createRouter(init) {
|
|
|
2853
2905
|
|
|
2854
2906
|
router = {
|
|
2855
2907
|
get basename() {
|
|
2856
|
-
return
|
|
2908
|
+
return basename;
|
|
2857
2909
|
},
|
|
2858
2910
|
|
|
2859
2911
|
get state() {
|
|
@@ -2895,9 +2947,23 @@ const UNSAFE_DEFERRED_SYMBOL = Symbol("deferred");
|
|
|
2895
2947
|
function createStaticHandler(routes, opts) {
|
|
2896
2948
|
invariant(routes.length > 0, "You must provide a non-empty routes array to createStaticHandler");
|
|
2897
2949
|
let manifest = {};
|
|
2898
|
-
let detectErrorBoundary = (opts == null ? void 0 : opts.detectErrorBoundary) || defaultDetectErrorBoundary;
|
|
2899
|
-
let dataRoutes = convertRoutesToDataRoutes(routes, detectErrorBoundary, undefined, manifest);
|
|
2900
2950
|
let basename = (opts ? opts.basename : null) || "/";
|
|
2951
|
+
let mapRouteProperties;
|
|
2952
|
+
|
|
2953
|
+
if (opts != null && opts.mapRouteProperties) {
|
|
2954
|
+
mapRouteProperties = opts.mapRouteProperties;
|
|
2955
|
+
} else if (opts != null && opts.detectErrorBoundary) {
|
|
2956
|
+
// If they are still using the deprecated version, wrap it with the new API
|
|
2957
|
+
let detectErrorBoundary = opts.detectErrorBoundary;
|
|
2958
|
+
|
|
2959
|
+
mapRouteProperties = route => ({
|
|
2960
|
+
hasErrorBoundary: detectErrorBoundary(route)
|
|
2961
|
+
});
|
|
2962
|
+
} else {
|
|
2963
|
+
mapRouteProperties = defaultMapRouteProperties;
|
|
2964
|
+
}
|
|
2965
|
+
|
|
2966
|
+
let dataRoutes = convertRoutesToDataRoutes(routes, mapRouteProperties, undefined, manifest);
|
|
2901
2967
|
/**
|
|
2902
2968
|
* The query() method is intended for document requests, in which we want to
|
|
2903
2969
|
* call an optional action and potentially multiple loaders for all nested
|
|
@@ -3134,7 +3200,7 @@ function createStaticHandler(routes, opts) {
|
|
|
3134
3200
|
error
|
|
3135
3201
|
};
|
|
3136
3202
|
} else {
|
|
3137
|
-
result = await callLoaderOrAction("action", request, actionMatch, matches, manifest,
|
|
3203
|
+
result = await callLoaderOrAction("action", request, actionMatch, matches, manifest, mapRouteProperties, basename, true, isRouteRequest, requestContext);
|
|
3138
3204
|
|
|
3139
3205
|
if (request.signal.aborted) {
|
|
3140
3206
|
let method = isRouteRequest ? "queryRoute" : "query";
|
|
@@ -3257,7 +3323,7 @@ function createStaticHandler(routes, opts) {
|
|
|
3257
3323
|
};
|
|
3258
3324
|
}
|
|
3259
3325
|
|
|
3260
|
-
let results = await Promise.all([...matchesToLoad.map(match => callLoaderOrAction("loader", request, match, matches, manifest,
|
|
3326
|
+
let results = await Promise.all([...matchesToLoad.map(match => callLoaderOrAction("loader", request, match, matches, manifest, mapRouteProperties, basename, true, isRouteRequest, requestContext))]);
|
|
3261
3327
|
|
|
3262
3328
|
if (request.signal.aborted) {
|
|
3263
3329
|
let method = isRouteRequest ? "queryRoute" : "query";
|
|
@@ -3308,17 +3374,62 @@ function getStaticContextFromError(routes, context, error) {
|
|
|
3308
3374
|
|
|
3309
3375
|
function isSubmissionNavigation(opts) {
|
|
3310
3376
|
return opts != null && "formData" in opts;
|
|
3311
|
-
}
|
|
3312
|
-
// URLSearchParams so they behave identically to links with query params
|
|
3377
|
+
}
|
|
3313
3378
|
|
|
3379
|
+
function normalizeTo(location, matches, basename, prependBasename, to, fromRouteId, relative) {
|
|
3380
|
+
let contextualMatches;
|
|
3381
|
+
let activeRouteMatch;
|
|
3314
3382
|
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3383
|
+
if (fromRouteId != null && relative !== "path") {
|
|
3384
|
+
// Grab matches up to the calling route so our route-relative logic is
|
|
3385
|
+
// relative to the correct source route. When using relative:path,
|
|
3386
|
+
// fromRouteId is ignored since that is always relative to the current
|
|
3387
|
+
// location path
|
|
3388
|
+
contextualMatches = [];
|
|
3389
|
+
|
|
3390
|
+
for (let match of matches) {
|
|
3391
|
+
contextualMatches.push(match);
|
|
3392
|
+
|
|
3393
|
+
if (match.route.id === fromRouteId) {
|
|
3394
|
+
activeRouteMatch = match;
|
|
3395
|
+
break;
|
|
3396
|
+
}
|
|
3397
|
+
}
|
|
3398
|
+
} else {
|
|
3399
|
+
contextualMatches = matches;
|
|
3400
|
+
activeRouteMatch = matches[matches.length - 1];
|
|
3401
|
+
} // Resolve the relative path
|
|
3402
|
+
|
|
3403
|
+
|
|
3404
|
+
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
|
|
3405
|
+
// location, unlike when to="." and we just inherit the path.
|
|
3406
|
+
// See https://github.com/remix-run/remix/issues/927
|
|
3407
|
+
|
|
3408
|
+
if (to == null) {
|
|
3409
|
+
path.search = location.search;
|
|
3410
|
+
path.hash = location.hash;
|
|
3411
|
+
} // Add an ?index param for matched index routes if we don't already have one
|
|
3412
|
+
|
|
3413
|
+
|
|
3414
|
+
if ((to == null || to === "" || to === ".") && activeRouteMatch && activeRouteMatch.route.index && !hasNakedIndexQuery(path.search)) {
|
|
3415
|
+
path.search = path.search ? path.search.replace(/^\?/, "?index&") : "?index";
|
|
3416
|
+
} // If we're operating within a basename, prepend it to the pathname. If
|
|
3417
|
+
// this is a root navigation, then just use the raw basename which allows
|
|
3418
|
+
// the basename to have full control over the presence of a trailing slash
|
|
3419
|
+
// on root actions
|
|
3420
|
+
|
|
3421
|
+
|
|
3422
|
+
if (prependBasename && basename !== "/") {
|
|
3423
|
+
path.pathname = path.pathname === "/" ? basename : joinPaths([basename, path.pathname]);
|
|
3318
3424
|
}
|
|
3319
3425
|
|
|
3320
|
-
|
|
3426
|
+
return createPath(path);
|
|
3427
|
+
} // Normalize navigation options by converting formMethod=GET formData objects to
|
|
3428
|
+
// URLSearchParams so they behave identically to links with query params
|
|
3429
|
+
|
|
3321
3430
|
|
|
3431
|
+
function normalizeNavigateOptions(normalizeFormMethod, isFetcher, path, opts) {
|
|
3432
|
+
// Return location verbatim on non-submission navigations
|
|
3322
3433
|
if (!opts || !isSubmissionNavigation(opts)) {
|
|
3323
3434
|
return {
|
|
3324
3435
|
path
|
|
@@ -3340,7 +3451,7 @@ function normalizeNavigateOptions(to, future, opts, isFetcher) {
|
|
|
3340
3451
|
if (opts.formData) {
|
|
3341
3452
|
let formMethod = opts.formMethod || "get";
|
|
3342
3453
|
submission = {
|
|
3343
|
-
formMethod:
|
|
3454
|
+
formMethod: normalizeFormMethod ? formMethod.toUpperCase() : formMethod.toLowerCase(),
|
|
3344
3455
|
formAction: stripHashFromPath(path),
|
|
3345
3456
|
formEncType: opts && opts.formEncType || "application/x-www-form-urlencoded",
|
|
3346
3457
|
formData: opts.formData
|
|
@@ -3356,9 +3467,9 @@ function normalizeNavigateOptions(to, future, opts, isFetcher) {
|
|
|
3356
3467
|
|
|
3357
3468
|
|
|
3358
3469
|
let parsedPath = parsePath(path);
|
|
3359
|
-
let searchParams = convertFormDataToSearchParams(opts.formData); //
|
|
3360
|
-
//
|
|
3361
|
-
// any incoming ?index params
|
|
3470
|
+
let searchParams = convertFormDataToSearchParams(opts.formData); // On GET navigation submissions we can drop the ?index param from the
|
|
3471
|
+
// resulting location since all loaders will run. But fetcher GET submissions
|
|
3472
|
+
// only run a single loader so we need to preserve any incoming ?index params
|
|
3362
3473
|
|
|
3363
3474
|
if (isFetcher && parsedPath.search && hasNakedIndexQuery(parsedPath.search)) {
|
|
3364
3475
|
searchParams.append("index", "");
|
|
@@ -3390,11 +3501,7 @@ function getLoaderMatchesUntilBoundary(matches, boundaryId) {
|
|
|
3390
3501
|
function getMatchesToLoad(history, state, matches, submission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, fetchLoadMatches, routesToUse, basename, pendingActionData, pendingError) {
|
|
3391
3502
|
let actionResult = pendingError ? Object.values(pendingError)[0] : pendingActionData ? Object.values(pendingActionData)[0] : undefined;
|
|
3392
3503
|
let currentUrl = history.createURL(state.location);
|
|
3393
|
-
let nextUrl = history.createURL(location);
|
|
3394
|
-
let defaultShouldRevalidate = // Forced revalidation due to submission, useRevalidate, or X-Remix-Revalidate
|
|
3395
|
-
isRevalidationRequired || // Clicked the same link, resubmitted a GET form
|
|
3396
|
-
currentUrl.toString() === nextUrl.toString() || // Search params affect all loaders
|
|
3397
|
-
currentUrl.search !== nextUrl.search; // Pick navigation matches that are net-new or qualify for revalidation
|
|
3504
|
+
let nextUrl = history.createURL(location); // Pick navigation matches that are net-new or qualify for revalidation
|
|
3398
3505
|
|
|
3399
3506
|
let boundaryId = pendingError ? Object.keys(pendingError)[0] : undefined;
|
|
3400
3507
|
let boundaryMatches = getLoaderMatchesUntilBoundary(matches, boundaryId);
|
|
@@ -3426,7 +3533,10 @@ function getMatchesToLoad(history, state, matches, submission, location, isReval
|
|
|
3426
3533
|
nextParams: nextRouteMatch.params
|
|
3427
3534
|
}, submission, {
|
|
3428
3535
|
actionResult,
|
|
3429
|
-
defaultShouldRevalidate:
|
|
3536
|
+
defaultShouldRevalidate: // Forced revalidation due to submission, useRevalidator, or X-Remix-Revalidate
|
|
3537
|
+
isRevalidationRequired || // Clicked the same link, resubmitted a GET form
|
|
3538
|
+
currentUrl.toString() === nextUrl.toString() || // Search params affect all loaders
|
|
3539
|
+
currentUrl.search !== nextUrl.search || isNewRouteInstance(currentRouteMatch, nextRouteMatch)
|
|
3430
3540
|
}));
|
|
3431
3541
|
}); // Pick fetcher.loads that need to be revalidated
|
|
3432
3542
|
|
|
@@ -3441,23 +3551,28 @@ function getMatchesToLoad(history, state, matches, submission, location, isReval
|
|
|
3441
3551
|
// we can trigger a 404 in callLoadersAndMaybeResolveData
|
|
3442
3552
|
|
|
3443
3553
|
if (!fetcherMatches) {
|
|
3444
|
-
revalidatingFetchers.push(
|
|
3445
|
-
key
|
|
3446
|
-
|
|
3554
|
+
revalidatingFetchers.push({
|
|
3555
|
+
key,
|
|
3556
|
+
routeId: f.routeId,
|
|
3557
|
+
path: f.path,
|
|
3447
3558
|
matches: null,
|
|
3448
|
-
match: null
|
|
3449
|
-
|
|
3559
|
+
match: null,
|
|
3560
|
+
controller: null
|
|
3561
|
+
});
|
|
3450
3562
|
return;
|
|
3451
3563
|
}
|
|
3452
3564
|
|
|
3453
3565
|
let fetcherMatch = getTargetMatch(fetcherMatches, f.path);
|
|
3454
3566
|
|
|
3455
3567
|
if (cancelledFetcherLoads.includes(key)) {
|
|
3456
|
-
revalidatingFetchers.push(
|
|
3568
|
+
revalidatingFetchers.push({
|
|
3457
3569
|
key,
|
|
3570
|
+
routeId: f.routeId,
|
|
3571
|
+
path: f.path,
|
|
3458
3572
|
matches: fetcherMatches,
|
|
3459
|
-
match: fetcherMatch
|
|
3460
|
-
|
|
3573
|
+
match: fetcherMatch,
|
|
3574
|
+
controller: new AbortController()
|
|
3575
|
+
});
|
|
3461
3576
|
return;
|
|
3462
3577
|
} // Revalidating fetchers are decoupled from the route matches since they
|
|
3463
3578
|
// hit a static href, so they _always_ check shouldRevalidate and the
|
|
@@ -3472,15 +3587,19 @@ function getMatchesToLoad(history, state, matches, submission, location, isReval
|
|
|
3472
3587
|
nextParams: matches[matches.length - 1].params
|
|
3473
3588
|
}, submission, {
|
|
3474
3589
|
actionResult,
|
|
3475
|
-
|
|
3590
|
+
// Forced revalidation due to submission, useRevalidator, or X-Remix-Revalidate
|
|
3591
|
+
defaultShouldRevalidate: isRevalidationRequired
|
|
3476
3592
|
}));
|
|
3477
3593
|
|
|
3478
3594
|
if (shouldRevalidate) {
|
|
3479
|
-
revalidatingFetchers.push(
|
|
3595
|
+
revalidatingFetchers.push({
|
|
3480
3596
|
key,
|
|
3597
|
+
routeId: f.routeId,
|
|
3598
|
+
path: f.path,
|
|
3481
3599
|
matches: fetcherMatches,
|
|
3482
|
-
match: fetcherMatch
|
|
3483
|
-
|
|
3600
|
+
match: fetcherMatch,
|
|
3601
|
+
controller: new AbortController()
|
|
3602
|
+
});
|
|
3484
3603
|
}
|
|
3485
3604
|
});
|
|
3486
3605
|
return [navigationMatches, revalidatingFetchers];
|
|
@@ -3524,7 +3643,7 @@ function shouldRevalidateLoader(loaderMatch, arg) {
|
|
|
3524
3643
|
*/
|
|
3525
3644
|
|
|
3526
3645
|
|
|
3527
|
-
async function loadLazyRouteModule(route,
|
|
3646
|
+
async function loadLazyRouteModule(route, mapRouteProperties, manifest) {
|
|
3528
3647
|
if (!route.lazy) {
|
|
3529
3648
|
return;
|
|
3530
3649
|
}
|
|
@@ -3560,27 +3679,19 @@ async function loadLazyRouteModule(route, detectErrorBoundary, manifest) {
|
|
|
3560
3679
|
routeUpdates[lazyRouteProperty] = lazyRoute[lazyRouteProperty];
|
|
3561
3680
|
}
|
|
3562
3681
|
} // Mutate the route with the provided updates. Do this first so we pass
|
|
3563
|
-
// the updated version to
|
|
3682
|
+
// the updated version to mapRouteProperties
|
|
3564
3683
|
|
|
3565
3684
|
|
|
3566
3685
|
Object.assign(routeToUpdate, routeUpdates); // Mutate the `hasErrorBoundary` property on the route based on the route
|
|
3567
3686
|
// updates and remove the `lazy` function so we don't resolve the lazy
|
|
3568
3687
|
// route again.
|
|
3569
3688
|
|
|
3570
|
-
Object.assign(routeToUpdate, {
|
|
3571
|
-
// To keep things framework agnostic, we use the provided
|
|
3572
|
-
// `detectErrorBoundary` function to set the `hasErrorBoundary` route
|
|
3573
|
-
// property since the logic will differ between frameworks.
|
|
3574
|
-
hasErrorBoundary: detectErrorBoundary(_extends({}, routeToUpdate)),
|
|
3689
|
+
Object.assign(routeToUpdate, _extends({}, mapRouteProperties(routeToUpdate), {
|
|
3575
3690
|
lazy: undefined
|
|
3576
|
-
});
|
|
3691
|
+
}));
|
|
3577
3692
|
}
|
|
3578
3693
|
|
|
3579
|
-
async function callLoaderOrAction(type, request, match, matches, manifest,
|
|
3580
|
-
if (basename === void 0) {
|
|
3581
|
-
basename = "/";
|
|
3582
|
-
}
|
|
3583
|
-
|
|
3694
|
+
async function callLoaderOrAction(type, request, match, matches, manifest, mapRouteProperties, basename, isStaticRequest, isRouteRequest, requestContext) {
|
|
3584
3695
|
if (isStaticRequest === void 0) {
|
|
3585
3696
|
isStaticRequest = false;
|
|
3586
3697
|
}
|
|
@@ -3614,11 +3725,11 @@ async function callLoaderOrAction(type, request, match, matches, manifest, detec
|
|
|
3614
3725
|
if (match.route.lazy) {
|
|
3615
3726
|
if (handler) {
|
|
3616
3727
|
// Run statically defined handler in parallel with lazy()
|
|
3617
|
-
let values = await Promise.all([runHandler(handler), loadLazyRouteModule(match.route,
|
|
3728
|
+
let values = await Promise.all([runHandler(handler), loadLazyRouteModule(match.route, mapRouteProperties, manifest)]);
|
|
3618
3729
|
result = values[0];
|
|
3619
3730
|
} else {
|
|
3620
3731
|
// Load lazy route module, then run any returned handler
|
|
3621
|
-
await loadLazyRouteModule(match.route,
|
|
3732
|
+
await loadLazyRouteModule(match.route, mapRouteProperties, manifest);
|
|
3622
3733
|
handler = match.route[type];
|
|
3623
3734
|
|
|
3624
3735
|
if (handler) {
|
|
@@ -3627,9 +3738,11 @@ async function callLoaderOrAction(type, request, match, matches, manifest, detec
|
|
|
3627
3738
|
// previously-lazy-loaded routes
|
|
3628
3739
|
result = await runHandler(handler);
|
|
3629
3740
|
} else if (type === "action") {
|
|
3741
|
+
let url = new URL(request.url);
|
|
3742
|
+
let pathname = url.pathname + url.search;
|
|
3630
3743
|
throw getInternalRouterError(405, {
|
|
3631
3744
|
method: request.method,
|
|
3632
|
-
pathname
|
|
3745
|
+
pathname,
|
|
3633
3746
|
routeId: match.route.id
|
|
3634
3747
|
});
|
|
3635
3748
|
} else {
|
|
@@ -3641,8 +3754,13 @@ async function callLoaderOrAction(type, request, match, matches, manifest, detec
|
|
|
3641
3754
|
};
|
|
3642
3755
|
}
|
|
3643
3756
|
}
|
|
3757
|
+
} else if (!handler) {
|
|
3758
|
+
let url = new URL(request.url);
|
|
3759
|
+
let pathname = url.pathname + url.search;
|
|
3760
|
+
throw getInternalRouterError(404, {
|
|
3761
|
+
pathname
|
|
3762
|
+
});
|
|
3644
3763
|
} else {
|
|
3645
|
-
invariant(handler, "Could not find the " + type + " to run on the \"" + match.route.id + "\" route");
|
|
3646
3764
|
result = await runHandler(handler);
|
|
3647
3765
|
}
|
|
3648
3766
|
|
|
@@ -3664,17 +3782,7 @@ async function callLoaderOrAction(type, request, match, matches, manifest, detec
|
|
|
3664
3782
|
invariant(location, "Redirects returned/thrown from loaders/actions must have a Location header"); // Support relative routing in internal redirects
|
|
3665
3783
|
|
|
3666
3784
|
if (!ABSOLUTE_URL_REGEX.test(location)) {
|
|
3667
|
-
|
|
3668
|
-
let routePathnames = getPathContributingMatches(activeMatches).map(match => match.pathnameBase);
|
|
3669
|
-
let resolvedLocation = resolveTo(location, routePathnames, new URL(request.url).pathname);
|
|
3670
|
-
invariant(createPath(resolvedLocation), "Unable to resolve redirect location: " + location); // Prepend the basename to the redirect location if we have one
|
|
3671
|
-
|
|
3672
|
-
if (basename) {
|
|
3673
|
-
let path = resolvedLocation.pathname;
|
|
3674
|
-
resolvedLocation.pathname = path === "/" ? basename : joinPaths([basename, path]);
|
|
3675
|
-
}
|
|
3676
|
-
|
|
3677
|
-
location = createPath(resolvedLocation);
|
|
3785
|
+
location = normalizeTo(new URL(request.url), matches.slice(0, matches.indexOf(match) + 1), basename, true, location);
|
|
3678
3786
|
} else if (!isStaticRequest) {
|
|
3679
3787
|
// Strip off the protocol+origin for same-origin + same-basename absolute
|
|
3680
3788
|
// redirects. If this is a static request, we can let it go back to the
|
|
@@ -3890,12 +3998,16 @@ function processLoaderData(state, matches, matchesToLoad, results, pendingError,
|
|
|
3890
3998
|
for (let index = 0; index < revalidatingFetchers.length; index++) {
|
|
3891
3999
|
let {
|
|
3892
4000
|
key,
|
|
3893
|
-
match
|
|
4001
|
+
match,
|
|
4002
|
+
controller
|
|
3894
4003
|
} = revalidatingFetchers[index];
|
|
3895
4004
|
invariant(fetcherResults !== undefined && fetcherResults[index] !== undefined, "Did not find corresponding fetcher result");
|
|
3896
4005
|
let result = fetcherResults[index]; // Process fetcher non-redirect errors
|
|
3897
4006
|
|
|
3898
|
-
if (
|
|
4007
|
+
if (controller && controller.signal.aborted) {
|
|
4008
|
+
// Nothing to do for aborted fetchers
|
|
4009
|
+
continue;
|
|
4010
|
+
} else if (isErrorResult(result)) {
|
|
3899
4011
|
let boundaryMatch = findNearestBoundary(state.matches, match == null ? void 0 : match.route.id);
|
|
3900
4012
|
|
|
3901
4013
|
if (!(errors && errors[boundaryMatch.route.id])) {
|
|
@@ -4084,7 +4196,7 @@ function isMutationMethod(method) {
|
|
|
4084
4196
|
return validMutationMethods.has(method.toLowerCase());
|
|
4085
4197
|
}
|
|
4086
4198
|
|
|
4087
|
-
async function resolveDeferredResults(currentMatches, matchesToLoad, results,
|
|
4199
|
+
async function resolveDeferredResults(currentMatches, matchesToLoad, results, signals, isFetcher, currentLoaderData) {
|
|
4088
4200
|
for (let index = 0; index < results.length; index++) {
|
|
4089
4201
|
let result = results[index];
|
|
4090
4202
|
let match = matchesToLoad[index]; // If we don't have a match, then we can have a deferred result to do
|
|
@@ -4102,6 +4214,8 @@ async function resolveDeferredResults(currentMatches, matchesToLoad, results, si
|
|
|
4102
4214
|
// Note: we do not have to touch activeDeferreds here since we race them
|
|
4103
4215
|
// against the signal in resolveDeferredData and they'll get aborted
|
|
4104
4216
|
// there if needed
|
|
4217
|
+
let signal = signals[index];
|
|
4218
|
+
invariant(signal, "Expected an AbortSignal for revalidating fetcher deferred result");
|
|
4105
4219
|
await resolveDeferredData(result, signal, isFetcher).then(result => {
|
|
4106
4220
|
if (result) {
|
|
4107
4221
|
results[index] = result || results[index];
|