@remix-run/router 1.19.1 → 1.19.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/dist/index.d.ts +1 -1
- package/dist/router.cjs.js +246 -163
- package/dist/router.cjs.js.map +1 -1
- package/dist/router.js +241 -158
- package/dist/router.js.map +1 -1
- package/dist/router.umd.js +246 -163
- package/dist/router.umd.js.map +1 -1
- package/dist/router.umd.min.js +2 -2
- package/dist/router.umd.min.js.map +1 -1
- package/dist/utils.d.ts +10 -9
- package/index.ts +1 -1
- package/package.json +1 -1
- package/router.ts +334 -229
- package/utils.ts +12 -11
package/dist/router.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @remix-run/router v1.19.
|
|
2
|
+
* @remix-run/router v1.19.2
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -1550,7 +1550,7 @@ function createRouter(init) {
|
|
|
1550
1550
|
let pendingPatchRoutes = new Map();
|
|
1551
1551
|
// Flag to ignore the next history update, so we can revert the URL change on
|
|
1552
1552
|
// a POP navigation that was blocked by the user without touching router state
|
|
1553
|
-
let
|
|
1553
|
+
let unblockBlockerHistoryUpdate = undefined;
|
|
1554
1554
|
// Initialize the router, all side effects should be kicked off from here.
|
|
1555
1555
|
// Implemented as a Fluent API for ease of:
|
|
1556
1556
|
// let router = createRouter(init).initialize();
|
|
@@ -1565,8 +1565,9 @@ function createRouter(init) {
|
|
|
1565
1565
|
} = _ref;
|
|
1566
1566
|
// Ignore this event if it was just us resetting the URL from a
|
|
1567
1567
|
// blocked POP navigation
|
|
1568
|
-
if (
|
|
1569
|
-
|
|
1568
|
+
if (unblockBlockerHistoryUpdate) {
|
|
1569
|
+
unblockBlockerHistoryUpdate();
|
|
1570
|
+
unblockBlockerHistoryUpdate = undefined;
|
|
1570
1571
|
return;
|
|
1571
1572
|
}
|
|
1572
1573
|
warning(blockerFunctions.size === 0 || delta != null, "You are trying to use a blocker on a POP navigation to a location " + "that was not created by @remix-run/router. This will fail silently in " + "production. This can happen if you are navigating outside the router " + "via `window.history.pushState`/`window.location.hash` instead of using " + "router navigation APIs. This can also happen if you are using " + "createHashRouter and the user manually changes the URL.");
|
|
@@ -1577,7 +1578,9 @@ function createRouter(init) {
|
|
|
1577
1578
|
});
|
|
1578
1579
|
if (blockerKey && delta != null) {
|
|
1579
1580
|
// Restore the URL to match the current UI, but don't update router state
|
|
1580
|
-
|
|
1581
|
+
let nextHistoryUpdatePromise = new Promise(resolve => {
|
|
1582
|
+
unblockBlockerHistoryUpdate = resolve;
|
|
1583
|
+
});
|
|
1581
1584
|
init.history.go(delta * -1);
|
|
1582
1585
|
// Put the blocker into a blocked state
|
|
1583
1586
|
updateBlocker(blockerKey, {
|
|
@@ -1590,8 +1593,10 @@ function createRouter(init) {
|
|
|
1590
1593
|
reset: undefined,
|
|
1591
1594
|
location
|
|
1592
1595
|
});
|
|
1593
|
-
// Re-do the same POP navigation we just blocked
|
|
1594
|
-
|
|
1596
|
+
// Re-do the same POP navigation we just blocked, after the url
|
|
1597
|
+
// restoration is also complete. See:
|
|
1598
|
+
// https://github.com/remix-run/react-router/issues/11613
|
|
1599
|
+
nextHistoryUpdatePromise.then(() => init.history.go(delta));
|
|
1595
1600
|
},
|
|
1596
1601
|
reset() {
|
|
1597
1602
|
let blockers = new Map(state.blockers);
|
|
@@ -1890,7 +1895,9 @@ function createRouter(init) {
|
|
|
1890
1895
|
// navigation to the navigation.location but do not trigger an uninterrupted
|
|
1891
1896
|
// revalidation so that history correctly updates once the navigation completes
|
|
1892
1897
|
startNavigation(pendingAction || state.historyAction, state.navigation.location, {
|
|
1893
|
-
overrideNavigation: state.navigation
|
|
1898
|
+
overrideNavigation: state.navigation,
|
|
1899
|
+
// Proxy through any rending view transition
|
|
1900
|
+
enableViewTransition: pendingViewTransitionEnabled === true
|
|
1894
1901
|
});
|
|
1895
1902
|
}
|
|
1896
1903
|
// Start a navigation to the given action/location. Can optionally provide a
|
|
@@ -2079,8 +2086,8 @@ function createRouter(init) {
|
|
|
2079
2086
|
})
|
|
2080
2087
|
};
|
|
2081
2088
|
} else {
|
|
2082
|
-
let results = await callDataStrategy("action", request, [actionMatch], matches);
|
|
2083
|
-
result = results[
|
|
2089
|
+
let results = await callDataStrategy("action", state, request, [actionMatch], matches, null);
|
|
2090
|
+
result = results[actionMatch.route.id];
|
|
2084
2091
|
if (request.signal.aborted) {
|
|
2085
2092
|
return {
|
|
2086
2093
|
shortCircuited: true
|
|
@@ -2098,7 +2105,7 @@ function createRouter(init) {
|
|
|
2098
2105
|
let location = normalizeRedirectLocation(result.response.headers.get("Location"), new URL(request.url), basename);
|
|
2099
2106
|
replace = location === state.location.pathname + state.location.search;
|
|
2100
2107
|
}
|
|
2101
|
-
await startRedirectNavigation(request, result, {
|
|
2108
|
+
await startRedirectNavigation(request, result, true, {
|
|
2102
2109
|
submission,
|
|
2103
2110
|
replace
|
|
2104
2111
|
});
|
|
@@ -2260,7 +2267,7 @@ function createRouter(init) {
|
|
|
2260
2267
|
let {
|
|
2261
2268
|
loaderResults,
|
|
2262
2269
|
fetcherResults
|
|
2263
|
-
} = await callLoadersAndMaybeResolveData(state
|
|
2270
|
+
} = await callLoadersAndMaybeResolveData(state, matches, matchesToLoad, revalidatingFetchers, request);
|
|
2264
2271
|
if (request.signal.aborted) {
|
|
2265
2272
|
return {
|
|
2266
2273
|
shortCircuited: true
|
|
@@ -2274,16 +2281,22 @@ function createRouter(init) {
|
|
|
2274
2281
|
}
|
|
2275
2282
|
revalidatingFetchers.forEach(rf => fetchControllers.delete(rf.key));
|
|
2276
2283
|
// If any loaders returned a redirect Response, start a new REPLACE navigation
|
|
2277
|
-
let redirect = findRedirect(
|
|
2284
|
+
let redirect = findRedirect(loaderResults);
|
|
2278
2285
|
if (redirect) {
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2286
|
+
await startRedirectNavigation(request, redirect.result, true, {
|
|
2287
|
+
replace
|
|
2288
|
+
});
|
|
2289
|
+
return {
|
|
2290
|
+
shortCircuited: true
|
|
2291
|
+
};
|
|
2292
|
+
}
|
|
2293
|
+
redirect = findRedirect(fetcherResults);
|
|
2294
|
+
if (redirect) {
|
|
2295
|
+
// If this redirect came from a fetcher make sure we mark it in
|
|
2296
|
+
// fetchRedirectIds so it doesn't get revalidated on the next set of
|
|
2297
|
+
// loader executions
|
|
2298
|
+
fetchRedirectIds.add(redirect.key);
|
|
2299
|
+
await startRedirectNavigation(request, redirect.result, true, {
|
|
2287
2300
|
replace
|
|
2288
2301
|
});
|
|
2289
2302
|
return {
|
|
@@ -2459,8 +2472,8 @@ function createRouter(init) {
|
|
|
2459
2472
|
// Call the action for the fetcher
|
|
2460
2473
|
fetchControllers.set(key, abortController);
|
|
2461
2474
|
let originatingLoadId = incrementingLoadId;
|
|
2462
|
-
let actionResults = await callDataStrategy("action", fetchRequest, [match], requestMatches);
|
|
2463
|
-
let actionResult = actionResults[
|
|
2475
|
+
let actionResults = await callDataStrategy("action", state, fetchRequest, [match], requestMatches, key);
|
|
2476
|
+
let actionResult = actionResults[match.route.id];
|
|
2464
2477
|
if (fetchRequest.signal.aborted) {
|
|
2465
2478
|
// We can delete this so long as we weren't aborted by our own fetcher
|
|
2466
2479
|
// re-submit which would have put _new_ controller is in fetchControllers
|
|
@@ -2491,7 +2504,7 @@ function createRouter(init) {
|
|
|
2491
2504
|
} else {
|
|
2492
2505
|
fetchRedirectIds.add(key);
|
|
2493
2506
|
updateFetcherState(key, getLoadingFetcher(submission));
|
|
2494
|
-
return startRedirectNavigation(fetchRequest, actionResult, {
|
|
2507
|
+
return startRedirectNavigation(fetchRequest, actionResult, false, {
|
|
2495
2508
|
fetcherSubmission: submission
|
|
2496
2509
|
});
|
|
2497
2510
|
}
|
|
@@ -2542,7 +2555,7 @@ function createRouter(init) {
|
|
|
2542
2555
|
let {
|
|
2543
2556
|
loaderResults,
|
|
2544
2557
|
fetcherResults
|
|
2545
|
-
} = await callLoadersAndMaybeResolveData(state
|
|
2558
|
+
} = await callLoadersAndMaybeResolveData(state, matches, matchesToLoad, revalidatingFetchers, revalidationRequest);
|
|
2546
2559
|
if (abortController.signal.aborted) {
|
|
2547
2560
|
return;
|
|
2548
2561
|
}
|
|
@@ -2550,22 +2563,23 @@ function createRouter(init) {
|
|
|
2550
2563
|
fetchReloadIds.delete(key);
|
|
2551
2564
|
fetchControllers.delete(key);
|
|
2552
2565
|
revalidatingFetchers.forEach(r => fetchControllers.delete(r.key));
|
|
2553
|
-
let redirect = findRedirect(
|
|
2566
|
+
let redirect = findRedirect(loaderResults);
|
|
2554
2567
|
if (redirect) {
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2568
|
+
return startRedirectNavigation(revalidationRequest, redirect.result, false);
|
|
2569
|
+
}
|
|
2570
|
+
redirect = findRedirect(fetcherResults);
|
|
2571
|
+
if (redirect) {
|
|
2572
|
+
// If this redirect came from a fetcher make sure we mark it in
|
|
2573
|
+
// fetchRedirectIds so it doesn't get revalidated on the next set of
|
|
2574
|
+
// loader executions
|
|
2575
|
+
fetchRedirectIds.add(redirect.key);
|
|
2576
|
+
return startRedirectNavigation(revalidationRequest, redirect.result, false);
|
|
2563
2577
|
}
|
|
2564
2578
|
// Process and commit output from loaders
|
|
2565
2579
|
let {
|
|
2566
2580
|
loaderData,
|
|
2567
2581
|
errors
|
|
2568
|
-
} = processLoaderData(state,
|
|
2582
|
+
} = processLoaderData(state, matches, matchesToLoad, loaderResults, undefined, revalidatingFetchers, fetcherResults, activeDeferreds);
|
|
2569
2583
|
// Since we let revalidations complete even if the submitting fetcher was
|
|
2570
2584
|
// deleted, only put it back to idle if it hasn't been deleted
|
|
2571
2585
|
if (state.fetchers.has(key)) {
|
|
@@ -2632,8 +2646,8 @@ function createRouter(init) {
|
|
|
2632
2646
|
// Call the loader for this fetcher route match
|
|
2633
2647
|
fetchControllers.set(key, abortController);
|
|
2634
2648
|
let originatingLoadId = incrementingLoadId;
|
|
2635
|
-
let results = await callDataStrategy("loader", fetchRequest, [match], matches);
|
|
2636
|
-
let result = results[
|
|
2649
|
+
let results = await callDataStrategy("loader", state, fetchRequest, [match], matches, key);
|
|
2650
|
+
let result = results[match.route.id];
|
|
2637
2651
|
// Deferred isn't supported for fetcher loads, await everything and treat it
|
|
2638
2652
|
// as a normal load. resolveDeferredData will return undefined if this
|
|
2639
2653
|
// fetcher gets aborted, so we just leave result untouched and short circuit
|
|
@@ -2664,7 +2678,7 @@ function createRouter(init) {
|
|
|
2664
2678
|
return;
|
|
2665
2679
|
} else {
|
|
2666
2680
|
fetchRedirectIds.add(key);
|
|
2667
|
-
await startRedirectNavigation(fetchRequest, result);
|
|
2681
|
+
await startRedirectNavigation(fetchRequest, result, false);
|
|
2668
2682
|
return;
|
|
2669
2683
|
}
|
|
2670
2684
|
}
|
|
@@ -2696,7 +2710,7 @@ function createRouter(init) {
|
|
|
2696
2710
|
* actually touch history until we've processed redirects, so we just use
|
|
2697
2711
|
* the history action from the original navigation (PUSH or REPLACE).
|
|
2698
2712
|
*/
|
|
2699
|
-
async function startRedirectNavigation(request, redirect, _temp2) {
|
|
2713
|
+
async function startRedirectNavigation(request, redirect, isNavigation, _temp2) {
|
|
2700
2714
|
let {
|
|
2701
2715
|
submission,
|
|
2702
2716
|
fetcherSubmission,
|
|
@@ -2756,8 +2770,9 @@ function createRouter(init) {
|
|
|
2756
2770
|
submission: _extends({}, activeSubmission, {
|
|
2757
2771
|
formAction: location
|
|
2758
2772
|
}),
|
|
2759
|
-
// Preserve
|
|
2760
|
-
preventScrollReset: pendingPreventScrollReset
|
|
2773
|
+
// Preserve these flags across redirects
|
|
2774
|
+
preventScrollReset: pendingPreventScrollReset,
|
|
2775
|
+
enableViewTransition: isNavigation ? pendingViewTransitionEnabled : undefined
|
|
2761
2776
|
});
|
|
2762
2777
|
} else {
|
|
2763
2778
|
// If we have a navigation submission, we will preserve it through the
|
|
@@ -2767,50 +2782,69 @@ function createRouter(init) {
|
|
|
2767
2782
|
overrideNavigation,
|
|
2768
2783
|
// Send fetcher submissions through for shouldRevalidate
|
|
2769
2784
|
fetcherSubmission,
|
|
2770
|
-
// Preserve
|
|
2771
|
-
preventScrollReset: pendingPreventScrollReset
|
|
2785
|
+
// Preserve these flags across redirects
|
|
2786
|
+
preventScrollReset: pendingPreventScrollReset,
|
|
2787
|
+
enableViewTransition: isNavigation ? pendingViewTransitionEnabled : undefined
|
|
2772
2788
|
});
|
|
2773
2789
|
}
|
|
2774
2790
|
}
|
|
2775
2791
|
// Utility wrapper for calling dataStrategy client-side without having to
|
|
2776
2792
|
// pass around the manifest, mapRouteProperties, etc.
|
|
2777
|
-
async function callDataStrategy(type, request, matchesToLoad, matches) {
|
|
2793
|
+
async function callDataStrategy(type, state, request, matchesToLoad, matches, fetcherKey) {
|
|
2794
|
+
let results;
|
|
2795
|
+
let dataResults = {};
|
|
2778
2796
|
try {
|
|
2779
|
-
|
|
2780
|
-
return await Promise.all(results.map((result, i) => {
|
|
2781
|
-
if (isRedirectHandlerResult(result)) {
|
|
2782
|
-
let response = result.result;
|
|
2783
|
-
return {
|
|
2784
|
-
type: ResultType.redirect,
|
|
2785
|
-
response: normalizeRelativeRoutingRedirectResponse(response, request, matchesToLoad[i].route.id, matches, basename, future.v7_relativeSplatPath)
|
|
2786
|
-
};
|
|
2787
|
-
}
|
|
2788
|
-
return convertHandlerResultToDataResult(result);
|
|
2789
|
-
}));
|
|
2797
|
+
results = await callDataStrategyImpl(dataStrategyImpl, type, state, request, matchesToLoad, matches, fetcherKey, manifest, mapRouteProperties);
|
|
2790
2798
|
} catch (e) {
|
|
2791
2799
|
// If the outer dataStrategy method throws, just return the error for all
|
|
2792
2800
|
// matches - and it'll naturally bubble to the root
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2801
|
+
matchesToLoad.forEach(m => {
|
|
2802
|
+
dataResults[m.route.id] = {
|
|
2803
|
+
type: ResultType.error,
|
|
2804
|
+
error: e
|
|
2805
|
+
};
|
|
2806
|
+
});
|
|
2807
|
+
return dataResults;
|
|
2808
|
+
}
|
|
2809
|
+
for (let [routeId, result] of Object.entries(results)) {
|
|
2810
|
+
if (isRedirectDataStrategyResultResult(result)) {
|
|
2811
|
+
let response = result.result;
|
|
2812
|
+
dataResults[routeId] = {
|
|
2813
|
+
type: ResultType.redirect,
|
|
2814
|
+
response: normalizeRelativeRoutingRedirectResponse(response, request, routeId, matches, basename, future.v7_relativeSplatPath)
|
|
2815
|
+
};
|
|
2816
|
+
} else {
|
|
2817
|
+
dataResults[routeId] = await convertDataStrategyResultToDataResult(result);
|
|
2818
|
+
}
|
|
2797
2819
|
}
|
|
2820
|
+
return dataResults;
|
|
2798
2821
|
}
|
|
2799
|
-
async function callLoadersAndMaybeResolveData(
|
|
2800
|
-
let
|
|
2822
|
+
async function callLoadersAndMaybeResolveData(state, matches, matchesToLoad, fetchersToLoad, request) {
|
|
2823
|
+
let currentMatches = state.matches;
|
|
2824
|
+
// Kick off loaders and fetchers in parallel
|
|
2825
|
+
let loaderResultsPromise = callDataStrategy("loader", state, request, matchesToLoad, matches, null);
|
|
2826
|
+
let fetcherResultsPromise = Promise.all(fetchersToLoad.map(async f => {
|
|
2801
2827
|
if (f.matches && f.match && f.controller) {
|
|
2802
|
-
let
|
|
2803
|
-
|
|
2828
|
+
let results = await callDataStrategy("loader", state, createClientSideRequest(init.history, f.path, f.controller.signal), [f.match], f.matches, f.key);
|
|
2829
|
+
let result = results[f.match.route.id];
|
|
2830
|
+
// Fetcher results are keyed by fetcher key from here on out, not routeId
|
|
2831
|
+
return {
|
|
2832
|
+
[f.key]: result
|
|
2833
|
+
};
|
|
2804
2834
|
} else {
|
|
2805
2835
|
return Promise.resolve({
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2836
|
+
[f.key]: {
|
|
2837
|
+
type: ResultType.error,
|
|
2838
|
+
error: getInternalRouterError(404, {
|
|
2839
|
+
pathname: f.path
|
|
2840
|
+
})
|
|
2841
|
+
}
|
|
2810
2842
|
});
|
|
2811
2843
|
}
|
|
2812
|
-
})
|
|
2813
|
-
|
|
2844
|
+
}));
|
|
2845
|
+
let loaderResults = await loaderResultsPromise;
|
|
2846
|
+
let fetcherResults = (await fetcherResultsPromise).reduce((acc, r) => Object.assign(acc, r), {});
|
|
2847
|
+
await Promise.all([resolveNavigationDeferredResults(matches, loaderResults, request.signal, currentMatches, state.loaderData), resolveFetcherDeferredResults(matches, fetcherResults, fetchersToLoad)]);
|
|
2814
2848
|
return {
|
|
2815
2849
|
loaderResults,
|
|
2816
2850
|
fetcherResults
|
|
@@ -3453,9 +3487,9 @@ function createStaticHandler(routes, opts) {
|
|
|
3453
3487
|
});
|
|
3454
3488
|
} catch (e) {
|
|
3455
3489
|
// If the user threw/returned a Response in callLoaderOrAction for a
|
|
3456
|
-
// `queryRoute` call, we throw the `
|
|
3490
|
+
// `queryRoute` call, we throw the `DataStrategyResult` to bail out early
|
|
3457
3491
|
// and then return or throw the raw Response here accordingly
|
|
3458
|
-
if (
|
|
3492
|
+
if (isDataStrategyResult(e) && isResponse(e.result)) {
|
|
3459
3493
|
if (e.type === ResultType.error) {
|
|
3460
3494
|
throw e.result;
|
|
3461
3495
|
}
|
|
@@ -3486,7 +3520,7 @@ function createStaticHandler(routes, opts) {
|
|
|
3486
3520
|
};
|
|
3487
3521
|
} else {
|
|
3488
3522
|
let results = await callDataStrategy("action", request, [actionMatch], matches, isRouteRequest, requestContext, unstable_dataStrategy);
|
|
3489
|
-
result = results[
|
|
3523
|
+
result = results[actionMatch.route.id];
|
|
3490
3524
|
if (request.signal.aborted) {
|
|
3491
3525
|
throwStaticHandlerAbortedError(request, isRouteRequest, future);
|
|
3492
3526
|
}
|
|
@@ -3603,7 +3637,7 @@ function createStaticHandler(routes, opts) {
|
|
|
3603
3637
|
}
|
|
3604
3638
|
// Process and commit output from loaders
|
|
3605
3639
|
let activeDeferreds = new Map();
|
|
3606
|
-
let context = processRouteLoaderData(matches,
|
|
3640
|
+
let context = processRouteLoaderData(matches, results, pendingActionResult, activeDeferreds, skipLoaderErrorBubbling);
|
|
3607
3641
|
// Add a null for any non-loader matches for proper revalidation on the client
|
|
3608
3642
|
let executedLoaders = new Set(matchesToLoad.map(match => match.route.id));
|
|
3609
3643
|
matches.forEach(match => {
|
|
@@ -3619,20 +3653,26 @@ function createStaticHandler(routes, opts) {
|
|
|
3619
3653
|
// Utility wrapper for calling dataStrategy server-side without having to
|
|
3620
3654
|
// pass around the manifest, mapRouteProperties, etc.
|
|
3621
3655
|
async function callDataStrategy(type, request, matchesToLoad, matches, isRouteRequest, requestContext, unstable_dataStrategy) {
|
|
3622
|
-
let results = await callDataStrategyImpl(unstable_dataStrategy || defaultDataStrategy, type, request, matchesToLoad, matches, manifest, mapRouteProperties, requestContext);
|
|
3623
|
-
|
|
3624
|
-
|
|
3656
|
+
let results = await callDataStrategyImpl(unstable_dataStrategy || defaultDataStrategy, type, null, request, matchesToLoad, matches, null, manifest, mapRouteProperties, requestContext);
|
|
3657
|
+
let dataResults = {};
|
|
3658
|
+
await Promise.all(matches.map(async match => {
|
|
3659
|
+
if (!(match.route.id in results)) {
|
|
3660
|
+
return;
|
|
3661
|
+
}
|
|
3662
|
+
let result = results[match.route.id];
|
|
3663
|
+
if (isRedirectDataStrategyResultResult(result)) {
|
|
3625
3664
|
let response = result.result;
|
|
3626
3665
|
// Throw redirects and let the server handle them with an HTTP redirect
|
|
3627
|
-
throw normalizeRelativeRoutingRedirectResponse(response, request,
|
|
3666
|
+
throw normalizeRelativeRoutingRedirectResponse(response, request, match.route.id, matches, basename, future.v7_relativeSplatPath);
|
|
3628
3667
|
}
|
|
3629
3668
|
if (isResponse(result.result) && isRouteRequest) {
|
|
3630
3669
|
// For SSR single-route requests, we want to hand Responses back
|
|
3631
3670
|
// directly without unwrapping
|
|
3632
3671
|
throw result;
|
|
3633
3672
|
}
|
|
3634
|
-
|
|
3673
|
+
dataResults[match.route.id] = await convertDataStrategyResultToDataResult(result);
|
|
3635
3674
|
}));
|
|
3675
|
+
return dataResults;
|
|
3636
3676
|
}
|
|
3637
3677
|
return {
|
|
3638
3678
|
dataRoutes,
|
|
@@ -4094,52 +4134,67 @@ async function loadLazyRouteModule(route, mapRouteProperties, manifest) {
|
|
|
4094
4134
|
}));
|
|
4095
4135
|
}
|
|
4096
4136
|
// Default implementation of `dataStrategy` which fetches all loaders in parallel
|
|
4097
|
-
function defaultDataStrategy(
|
|
4098
|
-
|
|
4137
|
+
async function defaultDataStrategy(_ref6) {
|
|
4138
|
+
let {
|
|
4139
|
+
matches
|
|
4140
|
+
} = _ref6;
|
|
4141
|
+
let matchesToLoad = matches.filter(m => m.shouldLoad);
|
|
4142
|
+
let results = await Promise.all(matchesToLoad.map(m => m.resolve()));
|
|
4143
|
+
return results.reduce((acc, result, i) => Object.assign(acc, {
|
|
4144
|
+
[matchesToLoad[i].route.id]: result
|
|
4145
|
+
}), {});
|
|
4099
4146
|
}
|
|
4100
|
-
async function callDataStrategyImpl(dataStrategyImpl, type, request, matchesToLoad, matches, manifest, mapRouteProperties, requestContext) {
|
|
4101
|
-
let
|
|
4102
|
-
let
|
|
4147
|
+
async function callDataStrategyImpl(dataStrategyImpl, type, state, request, matchesToLoad, matches, fetcherKey, manifest, mapRouteProperties, requestContext) {
|
|
4148
|
+
let loadRouteDefinitionsPromises = matches.map(m => m.route.lazy ? loadLazyRouteModule(m.route, mapRouteProperties, manifest) : undefined);
|
|
4149
|
+
let dsMatches = matches.map((match, i) => {
|
|
4150
|
+
let loadRoutePromise = loadRouteDefinitionsPromises[i];
|
|
4151
|
+
let shouldLoad = matchesToLoad.some(m => m.route.id === match.route.id);
|
|
4152
|
+
// `resolve` encapsulates route.lazy(), executing the loader/action,
|
|
4153
|
+
// and mapping return values/thrown errors to a `DataStrategyResult`. Users
|
|
4154
|
+
// can pass a callback to take fine-grained control over the execution
|
|
4155
|
+
// of the loader/action
|
|
4156
|
+
let resolve = async handlerOverride => {
|
|
4157
|
+
if (handlerOverride && request.method === "GET" && (match.route.lazy || match.route.loader)) {
|
|
4158
|
+
shouldLoad = true;
|
|
4159
|
+
}
|
|
4160
|
+
return shouldLoad ? callLoaderOrAction(type, request, match, loadRoutePromise, handlerOverride, requestContext) : Promise.resolve({
|
|
4161
|
+
type: ResultType.data,
|
|
4162
|
+
result: undefined
|
|
4163
|
+
});
|
|
4164
|
+
};
|
|
4165
|
+
return _extends({}, match, {
|
|
4166
|
+
shouldLoad,
|
|
4167
|
+
resolve
|
|
4168
|
+
});
|
|
4169
|
+
});
|
|
4103
4170
|
// Send all matches here to allow for a middleware-type implementation.
|
|
4104
4171
|
// handler will be a no-op for unneeded routes and we filter those results
|
|
4105
4172
|
// back out below.
|
|
4106
4173
|
let results = await dataStrategyImpl({
|
|
4107
|
-
matches:
|
|
4108
|
-
let shouldLoad = routeIdsToLoad.has(match.route.id);
|
|
4109
|
-
// `resolve` encapsulates the route.lazy, executing the
|
|
4110
|
-
// loader/action, and mapping return values/thrown errors to a
|
|
4111
|
-
// HandlerResult. Users can pass a callback to take fine-grained control
|
|
4112
|
-
// over the execution of the loader/action
|
|
4113
|
-
let resolve = handlerOverride => {
|
|
4114
|
-
loadedMatches.add(match.route.id);
|
|
4115
|
-
return shouldLoad ? callLoaderOrAction(type, request, match, manifest, mapRouteProperties, handlerOverride, requestContext) : Promise.resolve({
|
|
4116
|
-
type: ResultType.data,
|
|
4117
|
-
result: undefined
|
|
4118
|
-
});
|
|
4119
|
-
};
|
|
4120
|
-
return _extends({}, match, {
|
|
4121
|
-
shouldLoad,
|
|
4122
|
-
resolve
|
|
4123
|
-
});
|
|
4124
|
-
}),
|
|
4174
|
+
matches: dsMatches,
|
|
4125
4175
|
request,
|
|
4126
4176
|
params: matches[0].params,
|
|
4177
|
+
fetcherKey,
|
|
4127
4178
|
context: requestContext
|
|
4128
4179
|
});
|
|
4129
|
-
//
|
|
4130
|
-
//
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4180
|
+
// Wait for all routes to load here but 'swallow the error since we want
|
|
4181
|
+
// it to bubble up from the `await loadRoutePromise` in `callLoaderOrAction` -
|
|
4182
|
+
// called from `match.resolve()`
|
|
4183
|
+
try {
|
|
4184
|
+
await Promise.all(loadRouteDefinitionsPromises);
|
|
4185
|
+
} catch (e) {
|
|
4186
|
+
// No-op
|
|
4187
|
+
}
|
|
4188
|
+
return results;
|
|
4134
4189
|
}
|
|
4135
4190
|
// Default logic for calling a loader/action is the user has no specified a dataStrategy
|
|
4136
|
-
async function callLoaderOrAction(type, request, match,
|
|
4191
|
+
async function callLoaderOrAction(type, request, match, loadRoutePromise, handlerOverride, staticContext) {
|
|
4137
4192
|
let result;
|
|
4138
4193
|
let onReject;
|
|
4139
4194
|
let runHandler = handler => {
|
|
4140
4195
|
// Setup a promise we can race against so that abort signals short circuit
|
|
4141
4196
|
let reject;
|
|
4142
|
-
// This will never resolve so safe to type it as Promise<
|
|
4197
|
+
// This will never resolve so safe to type it as Promise<DataStrategyResult> to
|
|
4143
4198
|
// satisfy the function return value
|
|
4144
4199
|
let abortPromise = new Promise((_, r) => reject = r);
|
|
4145
4200
|
onReject = () => reject();
|
|
@@ -4154,30 +4209,26 @@ async function callLoaderOrAction(type, request, match, manifest, mapRouteProper
|
|
|
4154
4209
|
context: staticContext
|
|
4155
4210
|
}, ...(ctx !== undefined ? [ctx] : []));
|
|
4156
4211
|
};
|
|
4157
|
-
let handlerPromise
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
}
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
result: e
|
|
4172
|
-
};
|
|
4173
|
-
}
|
|
4174
|
-
})();
|
|
4175
|
-
}
|
|
4212
|
+
let handlerPromise = (async () => {
|
|
4213
|
+
try {
|
|
4214
|
+
let val = await (handlerOverride ? handlerOverride(ctx => actualHandler(ctx)) : actualHandler());
|
|
4215
|
+
return {
|
|
4216
|
+
type: "data",
|
|
4217
|
+
result: val
|
|
4218
|
+
};
|
|
4219
|
+
} catch (e) {
|
|
4220
|
+
return {
|
|
4221
|
+
type: "error",
|
|
4222
|
+
result: e
|
|
4223
|
+
};
|
|
4224
|
+
}
|
|
4225
|
+
})();
|
|
4176
4226
|
return Promise.race([handlerPromise, abortPromise]);
|
|
4177
4227
|
};
|
|
4178
4228
|
try {
|
|
4179
4229
|
let handler = match.route[type];
|
|
4180
|
-
|
|
4230
|
+
// If we have a route.lazy promise, await that first
|
|
4231
|
+
if (loadRoutePromise) {
|
|
4181
4232
|
if (handler) {
|
|
4182
4233
|
// Run statically defined handler in parallel with lazy()
|
|
4183
4234
|
let handlerError;
|
|
@@ -4187,14 +4238,14 @@ async function callLoaderOrAction(type, request, match, manifest, mapRouteProper
|
|
|
4187
4238
|
// route has a boundary that can handle the error
|
|
4188
4239
|
runHandler(handler).catch(e => {
|
|
4189
4240
|
handlerError = e;
|
|
4190
|
-
}),
|
|
4241
|
+
}), loadRoutePromise]);
|
|
4191
4242
|
if (handlerError !== undefined) {
|
|
4192
4243
|
throw handlerError;
|
|
4193
4244
|
}
|
|
4194
4245
|
result = value;
|
|
4195
4246
|
} else {
|
|
4196
4247
|
// Load lazy route module, then run any returned handler
|
|
4197
|
-
await
|
|
4248
|
+
await loadRoutePromise;
|
|
4198
4249
|
handler = match.route[type];
|
|
4199
4250
|
if (handler) {
|
|
4200
4251
|
// Handler still runs even if we got interrupted to maintain consistency
|
|
@@ -4230,7 +4281,7 @@ async function callLoaderOrAction(type, request, match, manifest, mapRouteProper
|
|
|
4230
4281
|
invariant(result.result !== undefined, "You defined " + (type === "action" ? "an action" : "a loader") + " for route " + ("\"" + match.route.id + "\" but didn't return anything from your `" + type + "` ") + "function. Please return a value or `null`.");
|
|
4231
4282
|
} catch (e) {
|
|
4232
4283
|
// We should already be catching and converting normal handler executions to
|
|
4233
|
-
//
|
|
4284
|
+
// DataStrategyResults and returning them, so anything that throws here is an
|
|
4234
4285
|
// unexpected error we still need to wrap
|
|
4235
4286
|
return {
|
|
4236
4287
|
type: ResultType.error,
|
|
@@ -4243,11 +4294,11 @@ async function callLoaderOrAction(type, request, match, manifest, mapRouteProper
|
|
|
4243
4294
|
}
|
|
4244
4295
|
return result;
|
|
4245
4296
|
}
|
|
4246
|
-
async function
|
|
4297
|
+
async function convertDataStrategyResultToDataResult(dataStrategyResult) {
|
|
4247
4298
|
let {
|
|
4248
4299
|
result,
|
|
4249
4300
|
type
|
|
4250
|
-
} =
|
|
4301
|
+
} = dataStrategyResult;
|
|
4251
4302
|
if (isResponse(result)) {
|
|
4252
4303
|
let data;
|
|
4253
4304
|
try {
|
|
@@ -4400,7 +4451,7 @@ function convertSearchParamsToFormData(searchParams) {
|
|
|
4400
4451
|
}
|
|
4401
4452
|
return formData;
|
|
4402
4453
|
}
|
|
4403
|
-
function processRouteLoaderData(matches,
|
|
4454
|
+
function processRouteLoaderData(matches, results, pendingActionResult, activeDeferreds, skipLoaderErrorBubbling) {
|
|
4404
4455
|
// Fill in loaderData/errors from our loaders
|
|
4405
4456
|
let loaderData = {};
|
|
4406
4457
|
let errors = null;
|
|
@@ -4409,8 +4460,12 @@ function processRouteLoaderData(matches, matchesToLoad, results, pendingActionRe
|
|
|
4409
4460
|
let loaderHeaders = {};
|
|
4410
4461
|
let pendingError = pendingActionResult && isErrorResult(pendingActionResult[1]) ? pendingActionResult[1].error : undefined;
|
|
4411
4462
|
// Process loader results into state.loaderData/state.errors
|
|
4412
|
-
|
|
4413
|
-
|
|
4463
|
+
matches.forEach(match => {
|
|
4464
|
+
if (!(match.route.id in results)) {
|
|
4465
|
+
return;
|
|
4466
|
+
}
|
|
4467
|
+
let id = match.route.id;
|
|
4468
|
+
let result = results[id];
|
|
4414
4469
|
invariant(!isRedirectResult(result), "Cannot handle redirect results in processLoaderData");
|
|
4415
4470
|
if (isErrorResult(result)) {
|
|
4416
4471
|
let error = result.error;
|
|
@@ -4489,21 +4544,21 @@ function processLoaderData(state, matches, matchesToLoad, results, pendingAction
|
|
|
4489
4544
|
let {
|
|
4490
4545
|
loaderData,
|
|
4491
4546
|
errors
|
|
4492
|
-
} = processRouteLoaderData(matches,
|
|
4547
|
+
} = processRouteLoaderData(matches, results, pendingActionResult, activeDeferreds, false // This method is only called client side so we always want to bubble
|
|
4493
4548
|
);
|
|
4494
4549
|
// Process results from our revalidating fetchers
|
|
4495
|
-
|
|
4550
|
+
revalidatingFetchers.forEach(rf => {
|
|
4496
4551
|
let {
|
|
4497
4552
|
key,
|
|
4498
4553
|
match,
|
|
4499
4554
|
controller
|
|
4500
|
-
} =
|
|
4501
|
-
|
|
4502
|
-
|
|
4555
|
+
} = rf;
|
|
4556
|
+
let result = fetcherResults[key];
|
|
4557
|
+
invariant(result, "Did not find corresponding fetcher result");
|
|
4503
4558
|
// Process fetcher non-redirect errors
|
|
4504
4559
|
if (controller && controller.signal.aborted) {
|
|
4505
4560
|
// Nothing to do for aborted fetchers
|
|
4506
|
-
|
|
4561
|
+
return;
|
|
4507
4562
|
} else if (isErrorResult(result)) {
|
|
4508
4563
|
let boundaryMatch = findNearestBoundary(state.matches, match == null ? void 0 : match.route.id);
|
|
4509
4564
|
if (!(errors && errors[boundaryMatch.route.id])) {
|
|
@@ -4524,7 +4579,7 @@ function processLoaderData(state, matches, matchesToLoad, results, pendingAction
|
|
|
4524
4579
|
let doneFetcher = getDoneFetcher(result.data);
|
|
4525
4580
|
state.fetchers.set(key, doneFetcher);
|
|
4526
4581
|
}
|
|
4527
|
-
}
|
|
4582
|
+
});
|
|
4528
4583
|
return {
|
|
4529
4584
|
loaderData,
|
|
4530
4585
|
errors
|
|
@@ -4624,12 +4679,13 @@ function getInternalRouterError(status, _temp5) {
|
|
|
4624
4679
|
}
|
|
4625
4680
|
// Find any returned redirect errors, starting from the lowest match
|
|
4626
4681
|
function findRedirect(results) {
|
|
4627
|
-
|
|
4628
|
-
|
|
4682
|
+
let entries = Object.entries(results);
|
|
4683
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
4684
|
+
let [key, result] = entries[i];
|
|
4629
4685
|
if (isRedirectResult(result)) {
|
|
4630
4686
|
return {
|
|
4631
|
-
|
|
4632
|
-
|
|
4687
|
+
key,
|
|
4688
|
+
result
|
|
4633
4689
|
};
|
|
4634
4690
|
}
|
|
4635
4691
|
}
|
|
@@ -4661,10 +4717,10 @@ function isHashChangeOnly(a, b) {
|
|
|
4661
4717
|
function isPromise(val) {
|
|
4662
4718
|
return typeof val === "object" && val != null && "then" in val;
|
|
4663
4719
|
}
|
|
4664
|
-
function
|
|
4720
|
+
function isDataStrategyResult(result) {
|
|
4665
4721
|
return result != null && typeof result === "object" && "type" in result && "result" in result && (result.type === ResultType.data || result.type === ResultType.error);
|
|
4666
4722
|
}
|
|
4667
|
-
function
|
|
4723
|
+
function isRedirectDataStrategyResultResult(result) {
|
|
4668
4724
|
return isResponse(result.result) && redirectStatusCodes.has(result.result.status);
|
|
4669
4725
|
}
|
|
4670
4726
|
function isDeferredResult(result) {
|
|
@@ -4700,10 +4756,11 @@ function isValidMethod(method) {
|
|
|
4700
4756
|
function isMutationMethod(method) {
|
|
4701
4757
|
return validMutationMethods.has(method.toLowerCase());
|
|
4702
4758
|
}
|
|
4703
|
-
async function
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
let
|
|
4759
|
+
async function resolveNavigationDeferredResults(matches, results, signal, currentMatches, currentLoaderData) {
|
|
4760
|
+
let entries = Object.entries(results);
|
|
4761
|
+
for (let index = 0; index < entries.length; index++) {
|
|
4762
|
+
let [routeId, result] = entries[index];
|
|
4763
|
+
let match = matches.find(m => (m == null ? void 0 : m.route.id) === routeId);
|
|
4707
4764
|
// If we don't have a match, then we can have a deferred result to do
|
|
4708
4765
|
// anything with. This is for revalidating fetchers where the route was
|
|
4709
4766
|
// removed during HMR
|
|
@@ -4712,15 +4769,41 @@ async function resolveDeferredResults(currentMatches, matchesToLoad, results, si
|
|
|
4712
4769
|
}
|
|
4713
4770
|
let currentMatch = currentMatches.find(m => m.route.id === match.route.id);
|
|
4714
4771
|
let isRevalidatingLoader = currentMatch != null && !isNewRouteInstance(currentMatch, match) && (currentLoaderData && currentLoaderData[match.route.id]) !== undefined;
|
|
4715
|
-
if (isDeferredResult(result) &&
|
|
4772
|
+
if (isDeferredResult(result) && isRevalidatingLoader) {
|
|
4773
|
+
// Note: we do not have to touch activeDeferreds here since we race them
|
|
4774
|
+
// against the signal in resolveDeferredData and they'll get aborted
|
|
4775
|
+
// there if needed
|
|
4776
|
+
await resolveDeferredData(result, signal, false).then(result => {
|
|
4777
|
+
if (result) {
|
|
4778
|
+
results[routeId] = result;
|
|
4779
|
+
}
|
|
4780
|
+
});
|
|
4781
|
+
}
|
|
4782
|
+
}
|
|
4783
|
+
}
|
|
4784
|
+
async function resolveFetcherDeferredResults(matches, results, revalidatingFetchers) {
|
|
4785
|
+
for (let index = 0; index < revalidatingFetchers.length; index++) {
|
|
4786
|
+
let {
|
|
4787
|
+
key,
|
|
4788
|
+
routeId,
|
|
4789
|
+
controller
|
|
4790
|
+
} = revalidatingFetchers[index];
|
|
4791
|
+
let result = results[key];
|
|
4792
|
+
let match = matches.find(m => (m == null ? void 0 : m.route.id) === routeId);
|
|
4793
|
+
// If we don't have a match, then we can have a deferred result to do
|
|
4794
|
+
// anything with. This is for revalidating fetchers where the route was
|
|
4795
|
+
// removed during HMR
|
|
4796
|
+
if (!match) {
|
|
4797
|
+
continue;
|
|
4798
|
+
}
|
|
4799
|
+
if (isDeferredResult(result)) {
|
|
4716
4800
|
// Note: we do not have to touch activeDeferreds here since we race them
|
|
4717
4801
|
// against the signal in resolveDeferredData and they'll get aborted
|
|
4718
4802
|
// there if needed
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
await resolveDeferredData(result, signal, isFetcher).then(result => {
|
|
4803
|
+
invariant(controller, "Expected an AbortController for revalidating fetcher deferred result");
|
|
4804
|
+
await resolveDeferredData(result, controller.signal, true).then(result => {
|
|
4722
4805
|
if (result) {
|
|
4723
|
-
results[
|
|
4806
|
+
results[key] = result;
|
|
4724
4807
|
}
|
|
4725
4808
|
});
|
|
4726
4809
|
}
|