@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.umd.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
|
*
|
|
@@ -578,7 +578,7 @@
|
|
|
578
578
|
// solely with AgnosticDataRouteObject's within the Router
|
|
579
579
|
|
|
580
580
|
|
|
581
|
-
function convertRoutesToDataRoutes(routes,
|
|
581
|
+
function convertRoutesToDataRoutes(routes, mapRouteProperties, parentPath, manifest) {
|
|
582
582
|
if (parentPath === void 0) {
|
|
583
583
|
parentPath = [];
|
|
584
584
|
}
|
|
@@ -594,24 +594,22 @@
|
|
|
594
594
|
invariant(!manifest[id], "Found a route id collision on id \"" + id + "\". Route " + "id's must be globally unique within Data Router usages");
|
|
595
595
|
|
|
596
596
|
if (isIndexRoute(route)) {
|
|
597
|
-
let indexRoute = _extends({}, route, {
|
|
598
|
-
hasErrorBoundary: detectErrorBoundary(route),
|
|
597
|
+
let indexRoute = _extends({}, route, mapRouteProperties(route), {
|
|
599
598
|
id
|
|
600
599
|
});
|
|
601
600
|
|
|
602
601
|
manifest[id] = indexRoute;
|
|
603
602
|
return indexRoute;
|
|
604
603
|
} else {
|
|
605
|
-
let pathOrLayoutRoute = _extends({}, route, {
|
|
604
|
+
let pathOrLayoutRoute = _extends({}, route, mapRouteProperties(route), {
|
|
606
605
|
id,
|
|
607
|
-
hasErrorBoundary: detectErrorBoundary(route),
|
|
608
606
|
children: undefined
|
|
609
607
|
});
|
|
610
608
|
|
|
611
609
|
manifest[id] = pathOrLayoutRoute;
|
|
612
610
|
|
|
613
611
|
if (route.children) {
|
|
614
|
-
pathOrLayoutRoute.children = convertRoutesToDataRoutes(route.children,
|
|
612
|
+
pathOrLayoutRoute.children = convertRoutesToDataRoutes(route.children, mapRouteProperties, treePath, manifest);
|
|
615
613
|
}
|
|
616
614
|
|
|
617
615
|
return pathOrLayoutRoute;
|
|
@@ -1473,7 +1471,9 @@
|
|
|
1473
1471
|
const isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined";
|
|
1474
1472
|
const isServer = !isBrowser;
|
|
1475
1473
|
|
|
1476
|
-
const
|
|
1474
|
+
const defaultMapRouteProperties = route => ({
|
|
1475
|
+
hasErrorBoundary: Boolean(route.hasErrorBoundary)
|
|
1476
|
+
}); //#endregion
|
|
1477
1477
|
////////////////////////////////////////////////////////////////////////////////
|
|
1478
1478
|
//#region createRouter
|
|
1479
1479
|
////////////////////////////////////////////////////////////////////////////////
|
|
@@ -1485,15 +1485,31 @@
|
|
|
1485
1485
|
|
|
1486
1486
|
function createRouter(init) {
|
|
1487
1487
|
invariant(init.routes.length > 0, "You must provide a non-empty routes array to createRouter");
|
|
1488
|
-
let
|
|
1488
|
+
let mapRouteProperties;
|
|
1489
|
+
|
|
1490
|
+
if (init.mapRouteProperties) {
|
|
1491
|
+
mapRouteProperties = init.mapRouteProperties;
|
|
1492
|
+
} else if (init.detectErrorBoundary) {
|
|
1493
|
+
// If they are still using the deprecated version, wrap it with the new API
|
|
1494
|
+
let detectErrorBoundary = init.detectErrorBoundary;
|
|
1495
|
+
|
|
1496
|
+
mapRouteProperties = route => ({
|
|
1497
|
+
hasErrorBoundary: detectErrorBoundary(route)
|
|
1498
|
+
});
|
|
1499
|
+
} else {
|
|
1500
|
+
mapRouteProperties = defaultMapRouteProperties;
|
|
1501
|
+
} // Routes keyed by ID
|
|
1502
|
+
|
|
1489
1503
|
|
|
1490
1504
|
let manifest = {}; // Routes in tree format for matching
|
|
1491
1505
|
|
|
1492
|
-
let dataRoutes = convertRoutesToDataRoutes(init.routes,
|
|
1493
|
-
let inFlightDataRoutes;
|
|
1506
|
+
let dataRoutes = convertRoutesToDataRoutes(init.routes, mapRouteProperties, undefined, manifest);
|
|
1507
|
+
let inFlightDataRoutes;
|
|
1508
|
+
let basename = init.basename || "/"; // Config driven behavior flags
|
|
1494
1509
|
|
|
1495
1510
|
let future = _extends({
|
|
1496
|
-
v7_normalizeFormMethod: false
|
|
1511
|
+
v7_normalizeFormMethod: false,
|
|
1512
|
+
v7_prependBasename: false
|
|
1497
1513
|
}, init.future); // Cleanup function for history
|
|
1498
1514
|
|
|
1499
1515
|
|
|
@@ -1513,7 +1529,7 @@
|
|
|
1513
1529
|
// SSR did the initial scroll restoration.
|
|
1514
1530
|
|
|
1515
1531
|
let initialScrollRestored = init.hydrationData != null;
|
|
1516
|
-
let initialMatches = matchRoutes(dataRoutes, init.history.location,
|
|
1532
|
+
let initialMatches = matchRoutes(dataRoutes, init.history.location, basename);
|
|
1517
1533
|
let initialErrors = null;
|
|
1518
1534
|
|
|
1519
1535
|
if (initialMatches == null) {
|
|
@@ -1565,7 +1581,7 @@
|
|
|
1565
1581
|
|
|
1566
1582
|
let isUninterruptedRevalidation = false; // Use this internal flag to force revalidation of all loaders:
|
|
1567
1583
|
// - submissions (completed or interrupted)
|
|
1568
|
-
// -
|
|
1584
|
+
// - useRevalidator()
|
|
1569
1585
|
// - X-Remix-Revalidate (from redirect)
|
|
1570
1586
|
|
|
1571
1587
|
let isRevalidationRequired = false; // Use this internal array to capture routes that require revalidation due
|
|
@@ -1584,7 +1600,7 @@
|
|
|
1584
1600
|
|
|
1585
1601
|
let pendingNavigationLoadId = -1; // Fetchers that triggered data reloads as a result of their actions
|
|
1586
1602
|
|
|
1587
|
-
let fetchReloadIds = new Map(); // Fetchers that triggered redirect navigations
|
|
1603
|
+
let fetchReloadIds = new Map(); // Fetchers that triggered redirect navigations
|
|
1588
1604
|
|
|
1589
1605
|
let fetchRedirectIds = new Set(); // Most recent href/match for fetcher.load calls for fetchers
|
|
1590
1606
|
|
|
@@ -1781,11 +1797,12 @@
|
|
|
1781
1797
|
return;
|
|
1782
1798
|
}
|
|
1783
1799
|
|
|
1800
|
+
let normalizedPath = normalizeTo(state.location, state.matches, basename, future.v7_prependBasename, to, opts == null ? void 0 : opts.fromRouteId, opts == null ? void 0 : opts.relative);
|
|
1784
1801
|
let {
|
|
1785
1802
|
path,
|
|
1786
1803
|
submission,
|
|
1787
1804
|
error
|
|
1788
|
-
} = normalizeNavigateOptions(
|
|
1805
|
+
} = normalizeNavigateOptions(future.v7_normalizeFormMethod, false, normalizedPath, opts);
|
|
1789
1806
|
let currentLocation = state.location;
|
|
1790
1807
|
let nextLocation = createLocation(state.location, path, opts && opts.state); // When using navigate as a PUSH/REPLACE we aren't reading an already-encoded
|
|
1791
1808
|
// URL from window.location, so we need to encode it here so the behavior
|
|
@@ -1901,7 +1918,7 @@
|
|
|
1901
1918
|
pendingPreventScrollReset = (opts && opts.preventScrollReset) === true;
|
|
1902
1919
|
let routesToUse = inFlightDataRoutes || dataRoutes;
|
|
1903
1920
|
let loadingNavigation = opts && opts.overrideNavigation;
|
|
1904
|
-
let matches = matchRoutes(routesToUse, location,
|
|
1921
|
+
let matches = matchRoutes(routesToUse, location, basename); // Short circuit with a 404 on the root error boundary if we match nothing
|
|
1905
1922
|
|
|
1906
1923
|
if (!matches) {
|
|
1907
1924
|
let error = getInternalRouterError(404, {
|
|
@@ -2024,7 +2041,7 @@
|
|
|
2024
2041
|
})
|
|
2025
2042
|
};
|
|
2026
2043
|
} else {
|
|
2027
|
-
result = await callLoaderOrAction("action", request, actionMatch, matches, manifest,
|
|
2044
|
+
result = await callLoaderOrAction("action", request, actionMatch, matches, manifest, mapRouteProperties, basename);
|
|
2028
2045
|
|
|
2029
2046
|
if (request.signal.aborted) {
|
|
2030
2047
|
return {
|
|
@@ -2116,13 +2133,14 @@
|
|
|
2116
2133
|
formEncType: loadingNavigation.formEncType
|
|
2117
2134
|
} : undefined;
|
|
2118
2135
|
let routesToUse = inFlightDataRoutes || dataRoutes;
|
|
2119
|
-
let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, activeSubmission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, fetchLoadMatches, routesToUse,
|
|
2136
|
+
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
|
|
2120
2137
|
// about to reload. Note that if this is an action reload we would have
|
|
2121
2138
|
// already cancelled all pending deferreds so this would be a no-op
|
|
2122
2139
|
|
|
2123
2140
|
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
|
|
2124
2141
|
|
|
2125
2142
|
if (matchesToLoad.length === 0 && revalidatingFetchers.length === 0) {
|
|
2143
|
+
let updatedFetchers = markFetchRedirectsDone();
|
|
2126
2144
|
completeNavigation(location, _extends({
|
|
2127
2145
|
matches,
|
|
2128
2146
|
loaderData: {},
|
|
@@ -2130,6 +2148,8 @@
|
|
|
2130
2148
|
errors: pendingError || null
|
|
2131
2149
|
}, pendingActionData ? {
|
|
2132
2150
|
actionData: pendingActionData
|
|
2151
|
+
} : {}, updatedFetchers ? {
|
|
2152
|
+
fetchers: new Map(state.fetchers)
|
|
2133
2153
|
} : {}));
|
|
2134
2154
|
return {
|
|
2135
2155
|
shortCircuited: true
|
|
@@ -2167,7 +2187,21 @@
|
|
|
2167
2187
|
}
|
|
2168
2188
|
|
|
2169
2189
|
pendingNavigationLoadId = ++incrementingLoadId;
|
|
2170
|
-
revalidatingFetchers.forEach(rf =>
|
|
2190
|
+
revalidatingFetchers.forEach(rf => {
|
|
2191
|
+
if (rf.controller) {
|
|
2192
|
+
// Fetchers use an independent AbortController so that aborting a fetcher
|
|
2193
|
+
// (via deleteFetcher) does not abort the triggering navigation that
|
|
2194
|
+
// triggered the revalidation
|
|
2195
|
+
fetchControllers.set(rf.key, rf.controller);
|
|
2196
|
+
}
|
|
2197
|
+
}); // Proxy navigation abort through to revalidation fetchers
|
|
2198
|
+
|
|
2199
|
+
let abortPendingFetchRevalidations = () => revalidatingFetchers.forEach(f => abortFetcher(f.key));
|
|
2200
|
+
|
|
2201
|
+
if (pendingNavigationController) {
|
|
2202
|
+
pendingNavigationController.signal.addEventListener("abort", abortPendingFetchRevalidations);
|
|
2203
|
+
}
|
|
2204
|
+
|
|
2171
2205
|
let {
|
|
2172
2206
|
results,
|
|
2173
2207
|
loaderResults,
|
|
@@ -2183,6 +2217,10 @@
|
|
|
2183
2217
|
// reassigned to new controllers for the next navigation
|
|
2184
2218
|
|
|
2185
2219
|
|
|
2220
|
+
if (pendingNavigationController) {
|
|
2221
|
+
pendingNavigationController.signal.removeEventListener("abort", abortPendingFetchRevalidations);
|
|
2222
|
+
}
|
|
2223
|
+
|
|
2186
2224
|
revalidatingFetchers.forEach(rf => fetchControllers.delete(rf.key)); // If any loaders returned a redirect Response, start a new REPLACE navigation
|
|
2187
2225
|
|
|
2188
2226
|
let redirect = findRedirect(results);
|
|
@@ -2212,12 +2250,13 @@
|
|
|
2212
2250
|
}
|
|
2213
2251
|
});
|
|
2214
2252
|
});
|
|
2215
|
-
markFetchRedirectsDone();
|
|
2253
|
+
let updatedFetchers = markFetchRedirectsDone();
|
|
2216
2254
|
let didAbortFetchLoads = abortStaleFetchLoads(pendingNavigationLoadId);
|
|
2255
|
+
let shouldUpdateFetchers = updatedFetchers || didAbortFetchLoads || revalidatingFetchers.length > 0;
|
|
2217
2256
|
return _extends({
|
|
2218
2257
|
loaderData,
|
|
2219
2258
|
errors
|
|
2220
|
-
},
|
|
2259
|
+
}, shouldUpdateFetchers ? {
|
|
2221
2260
|
fetchers: new Map(state.fetchers)
|
|
2222
2261
|
} : {});
|
|
2223
2262
|
}
|
|
@@ -2234,11 +2273,12 @@
|
|
|
2234
2273
|
|
|
2235
2274
|
if (fetchControllers.has(key)) abortFetcher(key);
|
|
2236
2275
|
let routesToUse = inFlightDataRoutes || dataRoutes;
|
|
2237
|
-
let
|
|
2276
|
+
let normalizedPath = normalizeTo(state.location, state.matches, basename, future.v7_prependBasename, href, routeId, opts == null ? void 0 : opts.relative);
|
|
2277
|
+
let matches = matchRoutes(routesToUse, normalizedPath, basename);
|
|
2238
2278
|
|
|
2239
2279
|
if (!matches) {
|
|
2240
2280
|
setFetcherError(key, routeId, getInternalRouterError(404, {
|
|
2241
|
-
pathname:
|
|
2281
|
+
pathname: normalizedPath
|
|
2242
2282
|
}));
|
|
2243
2283
|
return;
|
|
2244
2284
|
}
|
|
@@ -2246,7 +2286,7 @@
|
|
|
2246
2286
|
let {
|
|
2247
2287
|
path,
|
|
2248
2288
|
submission
|
|
2249
|
-
} = normalizeNavigateOptions(
|
|
2289
|
+
} = normalizeNavigateOptions(future.v7_normalizeFormMethod, true, normalizedPath, opts);
|
|
2250
2290
|
let match = getTargetMatch(matches, path);
|
|
2251
2291
|
pendingPreventScrollReset = (opts && opts.preventScrollReset) === true;
|
|
2252
2292
|
|
|
@@ -2298,7 +2338,7 @@
|
|
|
2298
2338
|
let abortController = new AbortController();
|
|
2299
2339
|
let fetchRequest = createClientSideRequest(init.history, path, abortController.signal, submission);
|
|
2300
2340
|
fetchControllers.set(key, abortController);
|
|
2301
|
-
let actionResult = await callLoaderOrAction("action", fetchRequest, match, requestMatches, manifest,
|
|
2341
|
+
let actionResult = await callLoaderOrAction("action", fetchRequest, match, requestMatches, manifest, mapRouteProperties, basename);
|
|
2302
2342
|
|
|
2303
2343
|
if (fetchRequest.signal.aborted) {
|
|
2304
2344
|
// We can delete this so long as we weren't aborted by ou our own fetcher
|
|
@@ -2348,7 +2388,7 @@
|
|
|
2348
2388
|
let nextLocation = state.navigation.location || state.location;
|
|
2349
2389
|
let revalidationRequest = createClientSideRequest(init.history, nextLocation, abortController.signal);
|
|
2350
2390
|
let routesToUse = inFlightDataRoutes || dataRoutes;
|
|
2351
|
-
let matches = state.navigation.state !== "idle" ? matchRoutes(routesToUse, state.navigation.location,
|
|
2391
|
+
let matches = state.navigation.state !== "idle" ? matchRoutes(routesToUse, state.navigation.location, basename) : state.matches;
|
|
2352
2392
|
invariant(matches, "Didn't find any matches after fetcher action");
|
|
2353
2393
|
let loadId = ++incrementingLoadId;
|
|
2354
2394
|
fetchReloadIds.set(key, loadId);
|
|
@@ -2361,7 +2401,7 @@
|
|
|
2361
2401
|
});
|
|
2362
2402
|
|
|
2363
2403
|
state.fetchers.set(key, loadFetcher);
|
|
2364
|
-
let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, submission, nextLocation, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, fetchLoadMatches, routesToUse,
|
|
2404
|
+
let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, submission, nextLocation, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, fetchLoadMatches, routesToUse, basename, {
|
|
2365
2405
|
[match.route.id]: actionResult.data
|
|
2366
2406
|
}, undefined // No need to send through errors since we short circuit above
|
|
2367
2407
|
); // Put all revalidating fetchers into the loading state, except for the
|
|
@@ -2381,11 +2421,18 @@
|
|
|
2381
2421
|
" _hasFetcherDoneAnything ": true
|
|
2382
2422
|
};
|
|
2383
2423
|
state.fetchers.set(staleKey, revalidatingFetcher);
|
|
2384
|
-
|
|
2424
|
+
|
|
2425
|
+
if (rf.controller) {
|
|
2426
|
+
fetchControllers.set(staleKey, rf.controller);
|
|
2427
|
+
}
|
|
2385
2428
|
});
|
|
2386
2429
|
updateState({
|
|
2387
2430
|
fetchers: new Map(state.fetchers)
|
|
2388
2431
|
});
|
|
2432
|
+
|
|
2433
|
+
let abortPendingFetchRevalidations = () => revalidatingFetchers.forEach(rf => abortFetcher(rf.key));
|
|
2434
|
+
|
|
2435
|
+
abortController.signal.addEventListener("abort", abortPendingFetchRevalidations);
|
|
2389
2436
|
let {
|
|
2390
2437
|
results,
|
|
2391
2438
|
loaderResults,
|
|
@@ -2396,6 +2443,7 @@
|
|
|
2396
2443
|
return;
|
|
2397
2444
|
}
|
|
2398
2445
|
|
|
2446
|
+
abortController.signal.removeEventListener("abort", abortPendingFetchRevalidations);
|
|
2399
2447
|
fetchReloadIds.delete(key);
|
|
2400
2448
|
fetchControllers.delete(key);
|
|
2401
2449
|
revalidatingFetchers.forEach(r => fetchControllers.delete(r.key));
|
|
@@ -2470,14 +2518,14 @@
|
|
|
2470
2518
|
let abortController = new AbortController();
|
|
2471
2519
|
let fetchRequest = createClientSideRequest(init.history, path, abortController.signal);
|
|
2472
2520
|
fetchControllers.set(key, abortController);
|
|
2473
|
-
let result = await callLoaderOrAction("loader", fetchRequest, match, matches, manifest,
|
|
2521
|
+
let result = await callLoaderOrAction("loader", fetchRequest, match, matches, manifest, mapRouteProperties, basename); // Deferred isn't supported for fetcher loads, await everything and treat it
|
|
2474
2522
|
// as a normal load. resolveDeferredData will return undefined if this
|
|
2475
2523
|
// fetcher gets aborted, so we just leave result untouched and short circuit
|
|
2476
2524
|
// below if that happens
|
|
2477
2525
|
|
|
2478
2526
|
if (isDeferredResult(result)) {
|
|
2479
2527
|
result = (await resolveDeferredData(result, fetchRequest.signal, true)) || result;
|
|
2480
|
-
} // We can delete this so long as we weren't aborted by
|
|
2528
|
+
} // We can delete this so long as we weren't aborted by our our own fetcher
|
|
2481
2529
|
// re-load which would have put _new_ controller is in fetchControllers
|
|
2482
2530
|
|
|
2483
2531
|
|
|
@@ -2491,6 +2539,7 @@
|
|
|
2491
2539
|
|
|
2492
2540
|
|
|
2493
2541
|
if (isRedirectResult(result)) {
|
|
2542
|
+
fetchRedirectIds.add(key);
|
|
2494
2543
|
await startRedirectNavigation(state, result);
|
|
2495
2544
|
return;
|
|
2496
2545
|
} // Process any non-redirect errors thrown
|
|
@@ -2571,7 +2620,7 @@
|
|
|
2571
2620
|
|
|
2572
2621
|
if (ABSOLUTE_URL_REGEX.test(redirect.location) && isBrowser && typeof ((_window = window) == null ? void 0 : _window.location) !== "undefined") {
|
|
2573
2622
|
let url = init.history.createURL(redirect.location);
|
|
2574
|
-
let isDifferentBasename = stripBasename(url.pathname,
|
|
2623
|
+
let isDifferentBasename = stripBasename(url.pathname, basename) == null;
|
|
2575
2624
|
|
|
2576
2625
|
if (window.location.origin !== url.origin || isDifferentBasename) {
|
|
2577
2626
|
if (replace) {
|
|
@@ -2655,9 +2704,9 @@
|
|
|
2655
2704
|
// Call all navigation loaders and revalidating fetcher loaders in parallel,
|
|
2656
2705
|
// then slice off the results into separate arrays so we can handle them
|
|
2657
2706
|
// accordingly
|
|
2658
|
-
let results = await Promise.all([...matchesToLoad.map(match => callLoaderOrAction("loader", request, match, matches, manifest,
|
|
2659
|
-
if (f.matches && f.match) {
|
|
2660
|
-
return callLoaderOrAction("loader", createClientSideRequest(init.history, f.path,
|
|
2707
|
+
let results = await Promise.all([...matchesToLoad.map(match => callLoaderOrAction("loader", request, match, matches, manifest, mapRouteProperties, basename)), ...fetchersToLoad.map(f => {
|
|
2708
|
+
if (f.matches && f.match && f.controller) {
|
|
2709
|
+
return callLoaderOrAction("loader", createClientSideRequest(init.history, f.path, f.controller.signal), f.match, f.matches, manifest, mapRouteProperties, basename);
|
|
2661
2710
|
} else {
|
|
2662
2711
|
let error = {
|
|
2663
2712
|
type: ResultType.error,
|
|
@@ -2670,7 +2719,7 @@
|
|
|
2670
2719
|
})]);
|
|
2671
2720
|
let loaderResults = results.slice(0, matchesToLoad.length);
|
|
2672
2721
|
let fetcherResults = results.slice(matchesToLoad.length);
|
|
2673
|
-
await Promise.all([resolveDeferredResults(currentMatches, matchesToLoad, loaderResults, request.signal, false, state.loaderData), resolveDeferredResults(currentMatches, fetchersToLoad.map(f => f.match), fetcherResults,
|
|
2722
|
+
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)]);
|
|
2674
2723
|
return {
|
|
2675
2724
|
results,
|
|
2676
2725
|
loaderResults,
|
|
@@ -2737,6 +2786,7 @@
|
|
|
2737
2786
|
|
|
2738
2787
|
function markFetchRedirectsDone() {
|
|
2739
2788
|
let doneKeys = [];
|
|
2789
|
+
let updatedFetchers = false;
|
|
2740
2790
|
|
|
2741
2791
|
for (let key of fetchRedirectIds) {
|
|
2742
2792
|
let fetcher = state.fetchers.get(key);
|
|
@@ -2745,10 +2795,12 @@
|
|
|
2745
2795
|
if (fetcher.state === "loading") {
|
|
2746
2796
|
fetchRedirectIds.delete(key);
|
|
2747
2797
|
doneKeys.push(key);
|
|
2798
|
+
updatedFetchers = true;
|
|
2748
2799
|
}
|
|
2749
2800
|
}
|
|
2750
2801
|
|
|
2751
2802
|
markFetchersDone(doneKeys);
|
|
2803
|
+
return updatedFetchers;
|
|
2752
2804
|
}
|
|
2753
2805
|
|
|
2754
2806
|
function abortStaleFetchLoads(landedId) {
|
|
@@ -2908,7 +2960,7 @@
|
|
|
2908
2960
|
|
|
2909
2961
|
router = {
|
|
2910
2962
|
get basename() {
|
|
2911
|
-
return
|
|
2963
|
+
return basename;
|
|
2912
2964
|
},
|
|
2913
2965
|
|
|
2914
2966
|
get state() {
|
|
@@ -2950,9 +3002,23 @@
|
|
|
2950
3002
|
function createStaticHandler(routes, opts) {
|
|
2951
3003
|
invariant(routes.length > 0, "You must provide a non-empty routes array to createStaticHandler");
|
|
2952
3004
|
let manifest = {};
|
|
2953
|
-
let detectErrorBoundary = (opts == null ? void 0 : opts.detectErrorBoundary) || defaultDetectErrorBoundary;
|
|
2954
|
-
let dataRoutes = convertRoutesToDataRoutes(routes, detectErrorBoundary, undefined, manifest);
|
|
2955
3005
|
let basename = (opts ? opts.basename : null) || "/";
|
|
3006
|
+
let mapRouteProperties;
|
|
3007
|
+
|
|
3008
|
+
if (opts != null && opts.mapRouteProperties) {
|
|
3009
|
+
mapRouteProperties = opts.mapRouteProperties;
|
|
3010
|
+
} else if (opts != null && opts.detectErrorBoundary) {
|
|
3011
|
+
// If they are still using the deprecated version, wrap it with the new API
|
|
3012
|
+
let detectErrorBoundary = opts.detectErrorBoundary;
|
|
3013
|
+
|
|
3014
|
+
mapRouteProperties = route => ({
|
|
3015
|
+
hasErrorBoundary: detectErrorBoundary(route)
|
|
3016
|
+
});
|
|
3017
|
+
} else {
|
|
3018
|
+
mapRouteProperties = defaultMapRouteProperties;
|
|
3019
|
+
}
|
|
3020
|
+
|
|
3021
|
+
let dataRoutes = convertRoutesToDataRoutes(routes, mapRouteProperties, undefined, manifest);
|
|
2956
3022
|
/**
|
|
2957
3023
|
* The query() method is intended for document requests, in which we want to
|
|
2958
3024
|
* call an optional action and potentially multiple loaders for all nested
|
|
@@ -3189,7 +3255,7 @@
|
|
|
3189
3255
|
error
|
|
3190
3256
|
};
|
|
3191
3257
|
} else {
|
|
3192
|
-
result = await callLoaderOrAction("action", request, actionMatch, matches, manifest,
|
|
3258
|
+
result = await callLoaderOrAction("action", request, actionMatch, matches, manifest, mapRouteProperties, basename, true, isRouteRequest, requestContext);
|
|
3193
3259
|
|
|
3194
3260
|
if (request.signal.aborted) {
|
|
3195
3261
|
let method = isRouteRequest ? "queryRoute" : "query";
|
|
@@ -3312,7 +3378,7 @@
|
|
|
3312
3378
|
};
|
|
3313
3379
|
}
|
|
3314
3380
|
|
|
3315
|
-
let results = await Promise.all([...matchesToLoad.map(match => callLoaderOrAction("loader", request, match, matches, manifest,
|
|
3381
|
+
let results = await Promise.all([...matchesToLoad.map(match => callLoaderOrAction("loader", request, match, matches, manifest, mapRouteProperties, basename, true, isRouteRequest, requestContext))]);
|
|
3316
3382
|
|
|
3317
3383
|
if (request.signal.aborted) {
|
|
3318
3384
|
let method = isRouteRequest ? "queryRoute" : "query";
|
|
@@ -3363,17 +3429,62 @@
|
|
|
3363
3429
|
|
|
3364
3430
|
function isSubmissionNavigation(opts) {
|
|
3365
3431
|
return opts != null && "formData" in opts;
|
|
3366
|
-
}
|
|
3367
|
-
// URLSearchParams so they behave identically to links with query params
|
|
3432
|
+
}
|
|
3368
3433
|
|
|
3434
|
+
function normalizeTo(location, matches, basename, prependBasename, to, fromRouteId, relative) {
|
|
3435
|
+
let contextualMatches;
|
|
3436
|
+
let activeRouteMatch;
|
|
3369
3437
|
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3438
|
+
if (fromRouteId != null && relative !== "path") {
|
|
3439
|
+
// Grab matches up to the calling route so our route-relative logic is
|
|
3440
|
+
// relative to the correct source route. When using relative:path,
|
|
3441
|
+
// fromRouteId is ignored since that is always relative to the current
|
|
3442
|
+
// location path
|
|
3443
|
+
contextualMatches = [];
|
|
3444
|
+
|
|
3445
|
+
for (let match of matches) {
|
|
3446
|
+
contextualMatches.push(match);
|
|
3447
|
+
|
|
3448
|
+
if (match.route.id === fromRouteId) {
|
|
3449
|
+
activeRouteMatch = match;
|
|
3450
|
+
break;
|
|
3451
|
+
}
|
|
3452
|
+
}
|
|
3453
|
+
} else {
|
|
3454
|
+
contextualMatches = matches;
|
|
3455
|
+
activeRouteMatch = matches[matches.length - 1];
|
|
3456
|
+
} // Resolve the relative path
|
|
3457
|
+
|
|
3458
|
+
|
|
3459
|
+
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
|
|
3460
|
+
// location, unlike when to="." and we just inherit the path.
|
|
3461
|
+
// See https://github.com/remix-run/remix/issues/927
|
|
3462
|
+
|
|
3463
|
+
if (to == null) {
|
|
3464
|
+
path.search = location.search;
|
|
3465
|
+
path.hash = location.hash;
|
|
3466
|
+
} // Add an ?index param for matched index routes if we don't already have one
|
|
3467
|
+
|
|
3468
|
+
|
|
3469
|
+
if ((to == null || to === "" || to === ".") && activeRouteMatch && activeRouteMatch.route.index && !hasNakedIndexQuery(path.search)) {
|
|
3470
|
+
path.search = path.search ? path.search.replace(/^\?/, "?index&") : "?index";
|
|
3471
|
+
} // If we're operating within a basename, prepend it to the pathname. If
|
|
3472
|
+
// this is a root navigation, then just use the raw basename which allows
|
|
3473
|
+
// the basename to have full control over the presence of a trailing slash
|
|
3474
|
+
// on root actions
|
|
3475
|
+
|
|
3476
|
+
|
|
3477
|
+
if (prependBasename && basename !== "/") {
|
|
3478
|
+
path.pathname = path.pathname === "/" ? basename : joinPaths([basename, path.pathname]);
|
|
3373
3479
|
}
|
|
3374
3480
|
|
|
3375
|
-
|
|
3481
|
+
return createPath(path);
|
|
3482
|
+
} // Normalize navigation options by converting formMethod=GET formData objects to
|
|
3483
|
+
// URLSearchParams so they behave identically to links with query params
|
|
3484
|
+
|
|
3376
3485
|
|
|
3486
|
+
function normalizeNavigateOptions(normalizeFormMethod, isFetcher, path, opts) {
|
|
3487
|
+
// Return location verbatim on non-submission navigations
|
|
3377
3488
|
if (!opts || !isSubmissionNavigation(opts)) {
|
|
3378
3489
|
return {
|
|
3379
3490
|
path
|
|
@@ -3395,7 +3506,7 @@
|
|
|
3395
3506
|
if (opts.formData) {
|
|
3396
3507
|
let formMethod = opts.formMethod || "get";
|
|
3397
3508
|
submission = {
|
|
3398
|
-
formMethod:
|
|
3509
|
+
formMethod: normalizeFormMethod ? formMethod.toUpperCase() : formMethod.toLowerCase(),
|
|
3399
3510
|
formAction: stripHashFromPath(path),
|
|
3400
3511
|
formEncType: opts && opts.formEncType || "application/x-www-form-urlencoded",
|
|
3401
3512
|
formData: opts.formData
|
|
@@ -3411,9 +3522,9 @@
|
|
|
3411
3522
|
|
|
3412
3523
|
|
|
3413
3524
|
let parsedPath = parsePath(path);
|
|
3414
|
-
let searchParams = convertFormDataToSearchParams(opts.formData); //
|
|
3415
|
-
//
|
|
3416
|
-
// any incoming ?index params
|
|
3525
|
+
let searchParams = convertFormDataToSearchParams(opts.formData); // On GET navigation submissions we can drop the ?index param from the
|
|
3526
|
+
// resulting location since all loaders will run. But fetcher GET submissions
|
|
3527
|
+
// only run a single loader so we need to preserve any incoming ?index params
|
|
3417
3528
|
|
|
3418
3529
|
if (isFetcher && parsedPath.search && hasNakedIndexQuery(parsedPath.search)) {
|
|
3419
3530
|
searchParams.append("index", "");
|
|
@@ -3445,11 +3556,7 @@
|
|
|
3445
3556
|
function getMatchesToLoad(history, state, matches, submission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, fetchLoadMatches, routesToUse, basename, pendingActionData, pendingError) {
|
|
3446
3557
|
let actionResult = pendingError ? Object.values(pendingError)[0] : pendingActionData ? Object.values(pendingActionData)[0] : undefined;
|
|
3447
3558
|
let currentUrl = history.createURL(state.location);
|
|
3448
|
-
let nextUrl = history.createURL(location);
|
|
3449
|
-
let defaultShouldRevalidate = // Forced revalidation due to submission, useRevalidate, or X-Remix-Revalidate
|
|
3450
|
-
isRevalidationRequired || // Clicked the same link, resubmitted a GET form
|
|
3451
|
-
currentUrl.toString() === nextUrl.toString() || // Search params affect all loaders
|
|
3452
|
-
currentUrl.search !== nextUrl.search; // Pick navigation matches that are net-new or qualify for revalidation
|
|
3559
|
+
let nextUrl = history.createURL(location); // Pick navigation matches that are net-new or qualify for revalidation
|
|
3453
3560
|
|
|
3454
3561
|
let boundaryId = pendingError ? Object.keys(pendingError)[0] : undefined;
|
|
3455
3562
|
let boundaryMatches = getLoaderMatchesUntilBoundary(matches, boundaryId);
|
|
@@ -3481,7 +3588,10 @@
|
|
|
3481
3588
|
nextParams: nextRouteMatch.params
|
|
3482
3589
|
}, submission, {
|
|
3483
3590
|
actionResult,
|
|
3484
|
-
defaultShouldRevalidate:
|
|
3591
|
+
defaultShouldRevalidate: // Forced revalidation due to submission, useRevalidator, or X-Remix-Revalidate
|
|
3592
|
+
isRevalidationRequired || // Clicked the same link, resubmitted a GET form
|
|
3593
|
+
currentUrl.toString() === nextUrl.toString() || // Search params affect all loaders
|
|
3594
|
+
currentUrl.search !== nextUrl.search || isNewRouteInstance(currentRouteMatch, nextRouteMatch)
|
|
3485
3595
|
}));
|
|
3486
3596
|
}); // Pick fetcher.loads that need to be revalidated
|
|
3487
3597
|
|
|
@@ -3496,23 +3606,28 @@
|
|
|
3496
3606
|
// we can trigger a 404 in callLoadersAndMaybeResolveData
|
|
3497
3607
|
|
|
3498
3608
|
if (!fetcherMatches) {
|
|
3499
|
-
revalidatingFetchers.push(
|
|
3500
|
-
key
|
|
3501
|
-
|
|
3609
|
+
revalidatingFetchers.push({
|
|
3610
|
+
key,
|
|
3611
|
+
routeId: f.routeId,
|
|
3612
|
+
path: f.path,
|
|
3502
3613
|
matches: null,
|
|
3503
|
-
match: null
|
|
3504
|
-
|
|
3614
|
+
match: null,
|
|
3615
|
+
controller: null
|
|
3616
|
+
});
|
|
3505
3617
|
return;
|
|
3506
3618
|
}
|
|
3507
3619
|
|
|
3508
3620
|
let fetcherMatch = getTargetMatch(fetcherMatches, f.path);
|
|
3509
3621
|
|
|
3510
3622
|
if (cancelledFetcherLoads.includes(key)) {
|
|
3511
|
-
revalidatingFetchers.push(
|
|
3623
|
+
revalidatingFetchers.push({
|
|
3512
3624
|
key,
|
|
3625
|
+
routeId: f.routeId,
|
|
3626
|
+
path: f.path,
|
|
3513
3627
|
matches: fetcherMatches,
|
|
3514
|
-
match: fetcherMatch
|
|
3515
|
-
|
|
3628
|
+
match: fetcherMatch,
|
|
3629
|
+
controller: new AbortController()
|
|
3630
|
+
});
|
|
3516
3631
|
return;
|
|
3517
3632
|
} // Revalidating fetchers are decoupled from the route matches since they
|
|
3518
3633
|
// hit a static href, so they _always_ check shouldRevalidate and the
|
|
@@ -3527,15 +3642,19 @@
|
|
|
3527
3642
|
nextParams: matches[matches.length - 1].params
|
|
3528
3643
|
}, submission, {
|
|
3529
3644
|
actionResult,
|
|
3530
|
-
|
|
3645
|
+
// Forced revalidation due to submission, useRevalidator, or X-Remix-Revalidate
|
|
3646
|
+
defaultShouldRevalidate: isRevalidationRequired
|
|
3531
3647
|
}));
|
|
3532
3648
|
|
|
3533
3649
|
if (shouldRevalidate) {
|
|
3534
|
-
revalidatingFetchers.push(
|
|
3650
|
+
revalidatingFetchers.push({
|
|
3535
3651
|
key,
|
|
3652
|
+
routeId: f.routeId,
|
|
3653
|
+
path: f.path,
|
|
3536
3654
|
matches: fetcherMatches,
|
|
3537
|
-
match: fetcherMatch
|
|
3538
|
-
|
|
3655
|
+
match: fetcherMatch,
|
|
3656
|
+
controller: new AbortController()
|
|
3657
|
+
});
|
|
3539
3658
|
}
|
|
3540
3659
|
});
|
|
3541
3660
|
return [navigationMatches, revalidatingFetchers];
|
|
@@ -3579,7 +3698,7 @@
|
|
|
3579
3698
|
*/
|
|
3580
3699
|
|
|
3581
3700
|
|
|
3582
|
-
async function loadLazyRouteModule(route,
|
|
3701
|
+
async function loadLazyRouteModule(route, mapRouteProperties, manifest) {
|
|
3583
3702
|
if (!route.lazy) {
|
|
3584
3703
|
return;
|
|
3585
3704
|
}
|
|
@@ -3615,27 +3734,19 @@
|
|
|
3615
3734
|
routeUpdates[lazyRouteProperty] = lazyRoute[lazyRouteProperty];
|
|
3616
3735
|
}
|
|
3617
3736
|
} // Mutate the route with the provided updates. Do this first so we pass
|
|
3618
|
-
// the updated version to
|
|
3737
|
+
// the updated version to mapRouteProperties
|
|
3619
3738
|
|
|
3620
3739
|
|
|
3621
3740
|
Object.assign(routeToUpdate, routeUpdates); // Mutate the `hasErrorBoundary` property on the route based on the route
|
|
3622
3741
|
// updates and remove the `lazy` function so we don't resolve the lazy
|
|
3623
3742
|
// route again.
|
|
3624
3743
|
|
|
3625
|
-
Object.assign(routeToUpdate, {
|
|
3626
|
-
// To keep things framework agnostic, we use the provided
|
|
3627
|
-
// `detectErrorBoundary` function to set the `hasErrorBoundary` route
|
|
3628
|
-
// property since the logic will differ between frameworks.
|
|
3629
|
-
hasErrorBoundary: detectErrorBoundary(_extends({}, routeToUpdate)),
|
|
3744
|
+
Object.assign(routeToUpdate, _extends({}, mapRouteProperties(routeToUpdate), {
|
|
3630
3745
|
lazy: undefined
|
|
3631
|
-
});
|
|
3746
|
+
}));
|
|
3632
3747
|
}
|
|
3633
3748
|
|
|
3634
|
-
async function callLoaderOrAction(type, request, match, matches, manifest,
|
|
3635
|
-
if (basename === void 0) {
|
|
3636
|
-
basename = "/";
|
|
3637
|
-
}
|
|
3638
|
-
|
|
3749
|
+
async function callLoaderOrAction(type, request, match, matches, manifest, mapRouteProperties, basename, isStaticRequest, isRouteRequest, requestContext) {
|
|
3639
3750
|
if (isStaticRequest === void 0) {
|
|
3640
3751
|
isStaticRequest = false;
|
|
3641
3752
|
}
|
|
@@ -3669,11 +3780,11 @@
|
|
|
3669
3780
|
if (match.route.lazy) {
|
|
3670
3781
|
if (handler) {
|
|
3671
3782
|
// Run statically defined handler in parallel with lazy()
|
|
3672
|
-
let values = await Promise.all([runHandler(handler), loadLazyRouteModule(match.route,
|
|
3783
|
+
let values = await Promise.all([runHandler(handler), loadLazyRouteModule(match.route, mapRouteProperties, manifest)]);
|
|
3673
3784
|
result = values[0];
|
|
3674
3785
|
} else {
|
|
3675
3786
|
// Load lazy route module, then run any returned handler
|
|
3676
|
-
await loadLazyRouteModule(match.route,
|
|
3787
|
+
await loadLazyRouteModule(match.route, mapRouteProperties, manifest);
|
|
3677
3788
|
handler = match.route[type];
|
|
3678
3789
|
|
|
3679
3790
|
if (handler) {
|
|
@@ -3682,9 +3793,11 @@
|
|
|
3682
3793
|
// previously-lazy-loaded routes
|
|
3683
3794
|
result = await runHandler(handler);
|
|
3684
3795
|
} else if (type === "action") {
|
|
3796
|
+
let url = new URL(request.url);
|
|
3797
|
+
let pathname = url.pathname + url.search;
|
|
3685
3798
|
throw getInternalRouterError(405, {
|
|
3686
3799
|
method: request.method,
|
|
3687
|
-
pathname
|
|
3800
|
+
pathname,
|
|
3688
3801
|
routeId: match.route.id
|
|
3689
3802
|
});
|
|
3690
3803
|
} else {
|
|
@@ -3696,8 +3809,13 @@
|
|
|
3696
3809
|
};
|
|
3697
3810
|
}
|
|
3698
3811
|
}
|
|
3812
|
+
} else if (!handler) {
|
|
3813
|
+
let url = new URL(request.url);
|
|
3814
|
+
let pathname = url.pathname + url.search;
|
|
3815
|
+
throw getInternalRouterError(404, {
|
|
3816
|
+
pathname
|
|
3817
|
+
});
|
|
3699
3818
|
} else {
|
|
3700
|
-
invariant(handler, "Could not find the " + type + " to run on the \"" + match.route.id + "\" route");
|
|
3701
3819
|
result = await runHandler(handler);
|
|
3702
3820
|
}
|
|
3703
3821
|
|
|
@@ -3719,17 +3837,7 @@
|
|
|
3719
3837
|
invariant(location, "Redirects returned/thrown from loaders/actions must have a Location header"); // Support relative routing in internal redirects
|
|
3720
3838
|
|
|
3721
3839
|
if (!ABSOLUTE_URL_REGEX.test(location)) {
|
|
3722
|
-
|
|
3723
|
-
let routePathnames = getPathContributingMatches(activeMatches).map(match => match.pathnameBase);
|
|
3724
|
-
let resolvedLocation = resolveTo(location, routePathnames, new URL(request.url).pathname);
|
|
3725
|
-
invariant(createPath(resolvedLocation), "Unable to resolve redirect location: " + location); // Prepend the basename to the redirect location if we have one
|
|
3726
|
-
|
|
3727
|
-
if (basename) {
|
|
3728
|
-
let path = resolvedLocation.pathname;
|
|
3729
|
-
resolvedLocation.pathname = path === "/" ? basename : joinPaths([basename, path]);
|
|
3730
|
-
}
|
|
3731
|
-
|
|
3732
|
-
location = createPath(resolvedLocation);
|
|
3840
|
+
location = normalizeTo(new URL(request.url), matches.slice(0, matches.indexOf(match) + 1), basename, true, location);
|
|
3733
3841
|
} else if (!isStaticRequest) {
|
|
3734
3842
|
// Strip off the protocol+origin for same-origin + same-basename absolute
|
|
3735
3843
|
// redirects. If this is a static request, we can let it go back to the
|
|
@@ -3945,12 +4053,16 @@
|
|
|
3945
4053
|
for (let index = 0; index < revalidatingFetchers.length; index++) {
|
|
3946
4054
|
let {
|
|
3947
4055
|
key,
|
|
3948
|
-
match
|
|
4056
|
+
match,
|
|
4057
|
+
controller
|
|
3949
4058
|
} = revalidatingFetchers[index];
|
|
3950
4059
|
invariant(fetcherResults !== undefined && fetcherResults[index] !== undefined, "Did not find corresponding fetcher result");
|
|
3951
4060
|
let result = fetcherResults[index]; // Process fetcher non-redirect errors
|
|
3952
4061
|
|
|
3953
|
-
if (
|
|
4062
|
+
if (controller && controller.signal.aborted) {
|
|
4063
|
+
// Nothing to do for aborted fetchers
|
|
4064
|
+
continue;
|
|
4065
|
+
} else if (isErrorResult(result)) {
|
|
3954
4066
|
let boundaryMatch = findNearestBoundary(state.matches, match == null ? void 0 : match.route.id);
|
|
3955
4067
|
|
|
3956
4068
|
if (!(errors && errors[boundaryMatch.route.id])) {
|
|
@@ -4139,7 +4251,7 @@
|
|
|
4139
4251
|
return validMutationMethods.has(method.toLowerCase());
|
|
4140
4252
|
}
|
|
4141
4253
|
|
|
4142
|
-
async function resolveDeferredResults(currentMatches, matchesToLoad, results,
|
|
4254
|
+
async function resolveDeferredResults(currentMatches, matchesToLoad, results, signals, isFetcher, currentLoaderData) {
|
|
4143
4255
|
for (let index = 0; index < results.length; index++) {
|
|
4144
4256
|
let result = results[index];
|
|
4145
4257
|
let match = matchesToLoad[index]; // If we don't have a match, then we can have a deferred result to do
|
|
@@ -4157,6 +4269,8 @@
|
|
|
4157
4269
|
// Note: we do not have to touch activeDeferreds here since we race them
|
|
4158
4270
|
// against the signal in resolveDeferredData and they'll get aborted
|
|
4159
4271
|
// there if needed
|
|
4272
|
+
let signal = signals[index];
|
|
4273
|
+
invariant(signal, "Expected an AbortSignal for revalidating fetcher deferred result");
|
|
4160
4274
|
await resolveDeferredData(result, signal, isFetcher).then(result => {
|
|
4161
4275
|
if (result) {
|
|
4162
4276
|
results[index] = result || results[index];
|