@remix-run/router 0.0.0-experimental-bcda00aaf → 0.0.0-experimental-1116190f7
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 +26 -0
- package/dist/router.cjs.js +163 -152
- package/dist/router.cjs.js.map +1 -1
- package/dist/router.js +156 -149
- package/dist/router.js.map +1 -1
- package/dist/router.umd.js +163 -152
- 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/package.json +1 -1
- package/router.ts +198 -189
package/dist/router.cjs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @remix-run/router v0.0.0-experimental-
|
|
2
|
+
* @remix-run/router v0.0.0-experimental-1116190f7
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -1741,6 +1741,7 @@ function createRouter(init) {
|
|
|
1741
1741
|
// SSR did the initial scroll restoration.
|
|
1742
1742
|
let initialScrollRestored = init.hydrationData != null;
|
|
1743
1743
|
let initialMatches = matchRoutes(dataRoutes, init.history.location, basename);
|
|
1744
|
+
let initialMatchesIsFOW = false;
|
|
1744
1745
|
let initialErrors = null;
|
|
1745
1746
|
if (initialMatches == null && !patchRoutesOnNavigationImpl) {
|
|
1746
1747
|
// If we do not match a user-provided-route, fall back to the root
|
|
@@ -1781,6 +1782,7 @@ function createRouter(init) {
|
|
|
1781
1782
|
if (future.v7_partialHydration) {
|
|
1782
1783
|
let fogOfWar = checkFogOfWar(null, dataRoutes, init.history.location.pathname);
|
|
1783
1784
|
if (fogOfWar.active && fogOfWar.matches) {
|
|
1785
|
+
initialMatchesIsFOW = true;
|
|
1784
1786
|
initialMatches = fogOfWar.matches;
|
|
1785
1787
|
}
|
|
1786
1788
|
}
|
|
@@ -1797,25 +1799,12 @@ function createRouter(init) {
|
|
|
1797
1799
|
// were marked for explicit hydration
|
|
1798
1800
|
let loaderData = init.hydrationData ? init.hydrationData.loaderData : null;
|
|
1799
1801
|
let errors = init.hydrationData ? init.hydrationData.errors : null;
|
|
1800
|
-
let isRouteInitialized = m => {
|
|
1801
|
-
// No loader, nothing to initialize
|
|
1802
|
-
if (!m.route.loader) {
|
|
1803
|
-
return true;
|
|
1804
|
-
}
|
|
1805
|
-
// Explicitly opting-in to running on hydration
|
|
1806
|
-
if (typeof m.route.loader === "function" && m.route.loader.hydrate === true) {
|
|
1807
|
-
return false;
|
|
1808
|
-
}
|
|
1809
|
-
// Otherwise, initialized if hydrated with data or an error
|
|
1810
|
-
return loaderData && loaderData[m.route.id] !== undefined || errors && errors[m.route.id] !== undefined;
|
|
1811
|
-
};
|
|
1812
|
-
|
|
1813
1802
|
// If errors exist, don't consider routes below the boundary
|
|
1814
1803
|
if (errors) {
|
|
1815
1804
|
let idx = initialMatches.findIndex(m => errors[m.route.id] !== undefined);
|
|
1816
|
-
initialized = initialMatches.slice(0, idx + 1).every(
|
|
1805
|
+
initialized = initialMatches.slice(0, idx + 1).every(m => !shouldLoadRouteOnHydration(m.route, loaderData, errors));
|
|
1817
1806
|
} else {
|
|
1818
|
-
initialized = initialMatches.every(
|
|
1807
|
+
initialized = initialMatches.every(m => !shouldLoadRouteOnHydration(m.route, loaderData, errors));
|
|
1819
1808
|
}
|
|
1820
1809
|
} else {
|
|
1821
1810
|
// Without partial hydration - we're initialized if we were provided any
|
|
@@ -1915,10 +1904,6 @@ function createRouter(init) {
|
|
|
1915
1904
|
// we don't need to update UI state if they change
|
|
1916
1905
|
let blockerFunctions = new Map();
|
|
1917
1906
|
|
|
1918
|
-
// Map of pending patchRoutesOnNavigation() promises (keyed by path/matches) so
|
|
1919
|
-
// that we only kick them off once for a given combo
|
|
1920
|
-
let pendingPatchRoutes = new Map();
|
|
1921
|
-
|
|
1922
1907
|
// Flag to ignore the next history update, so we can revert the URL change on
|
|
1923
1908
|
// a POP navigation that was blocked by the user without touching router state
|
|
1924
1909
|
let unblockBlockerHistoryUpdate = undefined;
|
|
@@ -2314,7 +2299,9 @@ function createRouter(init) {
|
|
|
2314
2299
|
pendingViewTransitionEnabled = (opts && opts.enableViewTransition) === true;
|
|
2315
2300
|
let routesToUse = inFlightDataRoutes || dataRoutes;
|
|
2316
2301
|
let loadingNavigation = opts && opts.overrideNavigation;
|
|
2317
|
-
let matches =
|
|
2302
|
+
let matches = opts != null && opts.initialHydration && state.matches && state.matches.length > 0 && !initialMatchesIsFOW ?
|
|
2303
|
+
// `matchRoutes()` has already been called if we're in here via `router.initialize()`
|
|
2304
|
+
state.matches : matchRoutes(routesToUse, location, basename);
|
|
2318
2305
|
let flushSync = (opts && opts.flushSync) === true;
|
|
2319
2306
|
let fogOfWar = checkFogOfWar(matches, routesToUse, location.pathname);
|
|
2320
2307
|
if (fogOfWar.active && fogOfWar.matches) {
|
|
@@ -2343,7 +2330,7 @@ function createRouter(init) {
|
|
|
2343
2330
|
// Short circuit if it's only a hash change and not a revalidation or
|
|
2344
2331
|
// mutation submission.
|
|
2345
2332
|
//
|
|
2346
|
-
// Ignore on initial page loads because since the initial
|
|
2333
|
+
// Ignore on initial page loads because since the initial hydration will always
|
|
2347
2334
|
// be "same hash". For example, on /page#hash and submit a <Form method="post">
|
|
2348
2335
|
// which will default to a navigation to /page
|
|
2349
2336
|
if (state.initialized && !isRevalidationRequired && isHashChangeOnly(state.location, location) && !(opts && opts.submission && isMutationMethod(opts.submission.formMethod))) {
|
|
@@ -2450,15 +2437,12 @@ function createRouter(init) {
|
|
|
2450
2437
|
shortCircuited: true
|
|
2451
2438
|
};
|
|
2452
2439
|
} else if (discoverResult.type === "error") {
|
|
2453
|
-
let
|
|
2454
|
-
boundaryId,
|
|
2455
|
-
error
|
|
2456
|
-
} = handleDiscoverRouteError(location.pathname, discoverResult);
|
|
2440
|
+
let boundaryId = findNearestBoundary(discoverResult.partialMatches).route.id;
|
|
2457
2441
|
return {
|
|
2458
2442
|
matches: discoverResult.partialMatches,
|
|
2459
2443
|
pendingActionResult: [boundaryId, {
|
|
2460
2444
|
type: ResultType.error,
|
|
2461
|
-
error
|
|
2445
|
+
error: discoverResult.error
|
|
2462
2446
|
}]
|
|
2463
2447
|
};
|
|
2464
2448
|
} else if (!discoverResult.matches) {
|
|
@@ -2588,15 +2572,12 @@ function createRouter(init) {
|
|
|
2588
2572
|
shortCircuited: true
|
|
2589
2573
|
};
|
|
2590
2574
|
} else if (discoverResult.type === "error") {
|
|
2591
|
-
let
|
|
2592
|
-
boundaryId,
|
|
2593
|
-
error
|
|
2594
|
-
} = handleDiscoverRouteError(location.pathname, discoverResult);
|
|
2575
|
+
let boundaryId = findNearestBoundary(discoverResult.partialMatches).route.id;
|
|
2595
2576
|
return {
|
|
2596
2577
|
matches: discoverResult.partialMatches,
|
|
2597
2578
|
loaderData: {},
|
|
2598
2579
|
errors: {
|
|
2599
|
-
[boundaryId]: error
|
|
2580
|
+
[boundaryId]: discoverResult.error
|
|
2600
2581
|
}
|
|
2601
2582
|
};
|
|
2602
2583
|
} else if (!discoverResult.matches) {
|
|
@@ -2662,9 +2643,7 @@ function createRouter(init) {
|
|
|
2662
2643
|
});
|
|
2663
2644
|
}
|
|
2664
2645
|
revalidatingFetchers.forEach(rf => {
|
|
2665
|
-
|
|
2666
|
-
abortFetcher(rf.key);
|
|
2667
|
-
}
|
|
2646
|
+
abortFetcher(rf.key);
|
|
2668
2647
|
if (rf.controller) {
|
|
2669
2648
|
// Fetchers use an independent AbortController so that aborting a fetcher
|
|
2670
2649
|
// (via deleteFetcher) does not abort the triggering navigation that
|
|
@@ -2724,7 +2703,7 @@ function createRouter(init) {
|
|
|
2724
2703
|
let {
|
|
2725
2704
|
loaderData,
|
|
2726
2705
|
errors
|
|
2727
|
-
} = processLoaderData(state, matches,
|
|
2706
|
+
} = processLoaderData(state, matches, loaderResults, pendingActionResult, revalidatingFetchers, fetcherResults, activeDeferreds);
|
|
2728
2707
|
|
|
2729
2708
|
// Wire up subscribers to update loaderData as promises settle
|
|
2730
2709
|
activeDeferreds.forEach((deferredData, routeId) => {
|
|
@@ -2738,17 +2717,9 @@ function createRouter(init) {
|
|
|
2738
2717
|
});
|
|
2739
2718
|
});
|
|
2740
2719
|
|
|
2741
|
-
//
|
|
2720
|
+
// Preserve SSR errors during partial hydration
|
|
2742
2721
|
if (future.v7_partialHydration && initialHydration && state.errors) {
|
|
2743
|
-
|
|
2744
|
-
let [id] = _ref2;
|
|
2745
|
-
return !matchesToLoad.some(m => m.route.id === id);
|
|
2746
|
-
}).forEach(_ref3 => {
|
|
2747
|
-
let [routeId, error] = _ref3;
|
|
2748
|
-
errors = Object.assign(errors || {}, {
|
|
2749
|
-
[routeId]: error
|
|
2750
|
-
});
|
|
2751
|
-
});
|
|
2722
|
+
errors = _extends({}, state.errors, errors);
|
|
2752
2723
|
}
|
|
2753
2724
|
let updatedFetchers = markFetchRedirectsDone();
|
|
2754
2725
|
let didAbortFetchLoads = abortStaleFetchLoads(pendingNavigationLoadId);
|
|
@@ -2791,7 +2762,7 @@ function createRouter(init) {
|
|
|
2791
2762
|
if (isServer) {
|
|
2792
2763
|
throw new Error("router.fetch() was called during the server render, but it shouldn't be. " + "You are likely calling a useFetcher() method in the body of your component. " + "Try moving it to a useEffect or a callback.");
|
|
2793
2764
|
}
|
|
2794
|
-
|
|
2765
|
+
abortFetcher(key);
|
|
2795
2766
|
let flushSync = (opts && opts.flushSync) === true;
|
|
2796
2767
|
let routesToUse = inFlightDataRoutes || dataRoutes;
|
|
2797
2768
|
let normalizedPath = normalizeTo(state.location, state.matches, basename, future.v7_prependBasename, href, future.v7_relativeSplatPath, routeId, opts == null ? void 0 : opts.relative);
|
|
@@ -2820,9 +2791,9 @@ function createRouter(init) {
|
|
|
2820
2791
|
return;
|
|
2821
2792
|
}
|
|
2822
2793
|
let match = getTargetMatch(matches, path);
|
|
2823
|
-
|
|
2794
|
+
let preventScrollReset = (opts && opts.preventScrollReset) === true;
|
|
2824
2795
|
if (submission && isMutationMethod(submission.formMethod)) {
|
|
2825
|
-
handleFetcherAction(key, routeId, path, match, matches, fogOfWar.active, flushSync, submission);
|
|
2796
|
+
handleFetcherAction(key, routeId, path, match, matches, fogOfWar.active, flushSync, preventScrollReset, submission);
|
|
2826
2797
|
return;
|
|
2827
2798
|
}
|
|
2828
2799
|
|
|
@@ -2832,12 +2803,12 @@ function createRouter(init) {
|
|
|
2832
2803
|
routeId,
|
|
2833
2804
|
path
|
|
2834
2805
|
});
|
|
2835
|
-
handleFetcherLoader(key, routeId, path, match, matches, fogOfWar.active, flushSync, submission);
|
|
2806
|
+
handleFetcherLoader(key, routeId, path, match, matches, fogOfWar.active, flushSync, preventScrollReset, submission);
|
|
2836
2807
|
}
|
|
2837
2808
|
|
|
2838
2809
|
// Call the action for the matched fetcher.submit(), and then handle redirects,
|
|
2839
2810
|
// errors, and revalidation
|
|
2840
|
-
async function handleFetcherAction(key, routeId, path, match, requestMatches, isFogOfWar, flushSync, submission) {
|
|
2811
|
+
async function handleFetcherAction(key, routeId, path, match, requestMatches, isFogOfWar, flushSync, preventScrollReset, submission) {
|
|
2841
2812
|
interruptActiveLoads();
|
|
2842
2813
|
fetchLoadMatches.delete(key);
|
|
2843
2814
|
function detectAndHandle405Error(m) {
|
|
@@ -2870,10 +2841,7 @@ function createRouter(init) {
|
|
|
2870
2841
|
if (discoverResult.type === "aborted") {
|
|
2871
2842
|
return;
|
|
2872
2843
|
} else if (discoverResult.type === "error") {
|
|
2873
|
-
|
|
2874
|
-
error
|
|
2875
|
-
} = handleDiscoverRouteError(path, discoverResult);
|
|
2876
|
-
setFetcherError(key, routeId, error, {
|
|
2844
|
+
setFetcherError(key, routeId, discoverResult.error, {
|
|
2877
2845
|
flushSync
|
|
2878
2846
|
});
|
|
2879
2847
|
return;
|
|
@@ -2930,7 +2898,8 @@ function createRouter(init) {
|
|
|
2930
2898
|
fetchRedirectIds.add(key);
|
|
2931
2899
|
updateFetcherState(key, getLoadingFetcher(submission));
|
|
2932
2900
|
return startRedirectNavigation(fetchRequest, actionResult, false, {
|
|
2933
|
-
fetcherSubmission: submission
|
|
2901
|
+
fetcherSubmission: submission,
|
|
2902
|
+
preventScrollReset
|
|
2934
2903
|
});
|
|
2935
2904
|
}
|
|
2936
2905
|
}
|
|
@@ -2968,9 +2937,7 @@ function createRouter(init) {
|
|
|
2968
2937
|
let existingFetcher = state.fetchers.get(staleKey);
|
|
2969
2938
|
let revalidatingFetcher = getLoadingFetcher(undefined, existingFetcher ? existingFetcher.data : undefined);
|
|
2970
2939
|
state.fetchers.set(staleKey, revalidatingFetcher);
|
|
2971
|
-
|
|
2972
|
-
abortFetcher(staleKey);
|
|
2973
|
-
}
|
|
2940
|
+
abortFetcher(staleKey);
|
|
2974
2941
|
if (rf.controller) {
|
|
2975
2942
|
fetchControllers.set(staleKey, rf.controller);
|
|
2976
2943
|
}
|
|
@@ -2993,7 +2960,9 @@ function createRouter(init) {
|
|
|
2993
2960
|
revalidatingFetchers.forEach(r => fetchControllers.delete(r.key));
|
|
2994
2961
|
let redirect = findRedirect(loaderResults);
|
|
2995
2962
|
if (redirect) {
|
|
2996
|
-
return startRedirectNavigation(revalidationRequest, redirect.result, false
|
|
2963
|
+
return startRedirectNavigation(revalidationRequest, redirect.result, false, {
|
|
2964
|
+
preventScrollReset
|
|
2965
|
+
});
|
|
2997
2966
|
}
|
|
2998
2967
|
redirect = findRedirect(fetcherResults);
|
|
2999
2968
|
if (redirect) {
|
|
@@ -3001,14 +2970,16 @@ function createRouter(init) {
|
|
|
3001
2970
|
// fetchRedirectIds so it doesn't get revalidated on the next set of
|
|
3002
2971
|
// loader executions
|
|
3003
2972
|
fetchRedirectIds.add(redirect.key);
|
|
3004
|
-
return startRedirectNavigation(revalidationRequest, redirect.result, false
|
|
2973
|
+
return startRedirectNavigation(revalidationRequest, redirect.result, false, {
|
|
2974
|
+
preventScrollReset
|
|
2975
|
+
});
|
|
3005
2976
|
}
|
|
3006
2977
|
|
|
3007
2978
|
// Process and commit output from loaders
|
|
3008
2979
|
let {
|
|
3009
2980
|
loaderData,
|
|
3010
2981
|
errors
|
|
3011
|
-
} = processLoaderData(state, matches,
|
|
2982
|
+
} = processLoaderData(state, matches, loaderResults, undefined, revalidatingFetchers, fetcherResults, activeDeferreds);
|
|
3012
2983
|
|
|
3013
2984
|
// Since we let revalidations complete even if the submitting fetcher was
|
|
3014
2985
|
// deleted, only put it back to idle if it hasn't been deleted
|
|
@@ -3044,7 +3015,7 @@ function createRouter(init) {
|
|
|
3044
3015
|
}
|
|
3045
3016
|
|
|
3046
3017
|
// Call the matched loader for fetcher.load(), handling redirects, errors, etc.
|
|
3047
|
-
async function handleFetcherLoader(key, routeId, path, match, matches, isFogOfWar, flushSync, submission) {
|
|
3018
|
+
async function handleFetcherLoader(key, routeId, path, match, matches, isFogOfWar, flushSync, preventScrollReset, submission) {
|
|
3048
3019
|
let existingFetcher = state.fetchers.get(key);
|
|
3049
3020
|
updateFetcherState(key, getLoadingFetcher(submission, existingFetcher ? existingFetcher.data : undefined), {
|
|
3050
3021
|
flushSync
|
|
@@ -3056,10 +3027,7 @@ function createRouter(init) {
|
|
|
3056
3027
|
if (discoverResult.type === "aborted") {
|
|
3057
3028
|
return;
|
|
3058
3029
|
} else if (discoverResult.type === "error") {
|
|
3059
|
-
|
|
3060
|
-
error
|
|
3061
|
-
} = handleDiscoverRouteError(path, discoverResult);
|
|
3062
|
-
setFetcherError(key, routeId, error, {
|
|
3030
|
+
setFetcherError(key, routeId, discoverResult.error, {
|
|
3063
3031
|
flushSync
|
|
3064
3032
|
});
|
|
3065
3033
|
return;
|
|
@@ -3115,7 +3083,9 @@ function createRouter(init) {
|
|
|
3115
3083
|
return;
|
|
3116
3084
|
} else {
|
|
3117
3085
|
fetchRedirectIds.add(key);
|
|
3118
|
-
await startRedirectNavigation(fetchRequest, result, false
|
|
3086
|
+
await startRedirectNavigation(fetchRequest, result, false, {
|
|
3087
|
+
preventScrollReset
|
|
3088
|
+
});
|
|
3119
3089
|
return;
|
|
3120
3090
|
}
|
|
3121
3091
|
}
|
|
@@ -3154,6 +3124,7 @@ function createRouter(init) {
|
|
|
3154
3124
|
let {
|
|
3155
3125
|
submission,
|
|
3156
3126
|
fetcherSubmission,
|
|
3127
|
+
preventScrollReset,
|
|
3157
3128
|
replace
|
|
3158
3129
|
} = _temp2 === void 0 ? {} : _temp2;
|
|
3159
3130
|
if (redirect.response.headers.has("X-Remix-Revalidate")) {
|
|
@@ -3214,7 +3185,7 @@ function createRouter(init) {
|
|
|
3214
3185
|
formAction: location
|
|
3215
3186
|
}),
|
|
3216
3187
|
// Preserve these flags across redirects
|
|
3217
|
-
preventScrollReset: pendingPreventScrollReset,
|
|
3188
|
+
preventScrollReset: preventScrollReset || pendingPreventScrollReset,
|
|
3218
3189
|
enableViewTransition: isNavigation ? pendingViewTransitionEnabled : undefined
|
|
3219
3190
|
});
|
|
3220
3191
|
} else {
|
|
@@ -3226,7 +3197,7 @@ function createRouter(init) {
|
|
|
3226
3197
|
// Send fetcher submissions through for shouldRevalidate
|
|
3227
3198
|
fetcherSubmission,
|
|
3228
3199
|
// Preserve these flags across redirects
|
|
3229
|
-
preventScrollReset: pendingPreventScrollReset,
|
|
3200
|
+
preventScrollReset: preventScrollReset || pendingPreventScrollReset,
|
|
3230
3201
|
enableViewTransition: isNavigation ? pendingViewTransitionEnabled : undefined
|
|
3231
3202
|
});
|
|
3232
3203
|
}
|
|
@@ -3307,8 +3278,8 @@ function createRouter(init) {
|
|
|
3307
3278
|
fetchLoadMatches.forEach((_, key) => {
|
|
3308
3279
|
if (fetchControllers.has(key)) {
|
|
3309
3280
|
cancelledFetcherLoads.add(key);
|
|
3310
|
-
abortFetcher(key);
|
|
3311
3281
|
}
|
|
3282
|
+
abortFetcher(key);
|
|
3312
3283
|
});
|
|
3313
3284
|
}
|
|
3314
3285
|
function updateFetcherState(key, fetcher, opts) {
|
|
@@ -3381,9 +3352,10 @@ function createRouter(init) {
|
|
|
3381
3352
|
}
|
|
3382
3353
|
function abortFetcher(key) {
|
|
3383
3354
|
let controller = fetchControllers.get(key);
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3355
|
+
if (controller) {
|
|
3356
|
+
controller.abort();
|
|
3357
|
+
fetchControllers.delete(key);
|
|
3358
|
+
}
|
|
3387
3359
|
}
|
|
3388
3360
|
function markFetchersDone(keys) {
|
|
3389
3361
|
for (let key of keys) {
|
|
@@ -3448,12 +3420,12 @@ function createRouter(init) {
|
|
|
3448
3420
|
blockers
|
|
3449
3421
|
});
|
|
3450
3422
|
}
|
|
3451
|
-
function shouldBlockNavigation(
|
|
3423
|
+
function shouldBlockNavigation(_ref2) {
|
|
3452
3424
|
let {
|
|
3453
3425
|
currentLocation,
|
|
3454
3426
|
nextLocation,
|
|
3455
3427
|
historyAction
|
|
3456
|
-
} =
|
|
3428
|
+
} = _ref2;
|
|
3457
3429
|
if (blockerFunctions.size === 0) {
|
|
3458
3430
|
return;
|
|
3459
3431
|
}
|
|
@@ -3500,16 +3472,6 @@ function createRouter(init) {
|
|
|
3500
3472
|
error
|
|
3501
3473
|
};
|
|
3502
3474
|
}
|
|
3503
|
-
function handleDiscoverRouteError(pathname, discoverResult) {
|
|
3504
|
-
return {
|
|
3505
|
-
boundaryId: findNearestBoundary(discoverResult.partialMatches).route.id,
|
|
3506
|
-
error: getInternalRouterError(400, {
|
|
3507
|
-
type: "route-discovery",
|
|
3508
|
-
pathname,
|
|
3509
|
-
message: discoverResult.error != null && "message" in discoverResult.error ? discoverResult.error : String(discoverResult.error)
|
|
3510
|
-
})
|
|
3511
|
-
};
|
|
3512
|
-
}
|
|
3513
3475
|
function cancelActiveDeferreds(predicate) {
|
|
3514
3476
|
let cancelledRouteIds = [];
|
|
3515
3477
|
activeDeferreds.forEach((dfd, routeId) => {
|
|
@@ -3600,12 +3562,26 @@ function createRouter(init) {
|
|
|
3600
3562
|
};
|
|
3601
3563
|
}
|
|
3602
3564
|
async function discoverRoutes(matches, pathname, signal) {
|
|
3565
|
+
if (!patchRoutesOnNavigationImpl) {
|
|
3566
|
+
return {
|
|
3567
|
+
type: "success",
|
|
3568
|
+
matches
|
|
3569
|
+
};
|
|
3570
|
+
}
|
|
3603
3571
|
let partialMatches = matches;
|
|
3604
3572
|
while (true) {
|
|
3605
3573
|
let isNonHMR = inFlightDataRoutes == null;
|
|
3606
3574
|
let routesToUse = inFlightDataRoutes || dataRoutes;
|
|
3575
|
+
let localManifest = manifest;
|
|
3607
3576
|
try {
|
|
3608
|
-
await
|
|
3577
|
+
await patchRoutesOnNavigationImpl({
|
|
3578
|
+
path: pathname,
|
|
3579
|
+
matches: partialMatches,
|
|
3580
|
+
patch: (routeId, children) => {
|
|
3581
|
+
if (signal.aborted) return;
|
|
3582
|
+
patchRoutesImpl(routeId, children, routesToUse, localManifest, mapRouteProperties);
|
|
3583
|
+
}
|
|
3584
|
+
});
|
|
3609
3585
|
} catch (e) {
|
|
3610
3586
|
return {
|
|
3611
3587
|
type: "error",
|
|
@@ -3619,7 +3595,7 @@ function createRouter(init) {
|
|
|
3619
3595
|
// trigger a re-run of memoized `router.routes` dependencies.
|
|
3620
3596
|
// HMR will already update the identity and reflow when it lands
|
|
3621
3597
|
// `inFlightDataRoutes` in `completeNavigation`
|
|
3622
|
-
if (isNonHMR) {
|
|
3598
|
+
if (isNonHMR && !signal.aborted) {
|
|
3623
3599
|
dataRoutes = [...dataRoutes];
|
|
3624
3600
|
}
|
|
3625
3601
|
}
|
|
@@ -4198,9 +4174,21 @@ function normalizeTo(location, matches, basename, prependBasename, to, v7_relati
|
|
|
4198
4174
|
path.hash = location.hash;
|
|
4199
4175
|
}
|
|
4200
4176
|
|
|
4201
|
-
//
|
|
4202
|
-
if ((to == null || to === "" || to === ".") && activeRouteMatch
|
|
4203
|
-
|
|
4177
|
+
// Account for `?index` params when routing to the current location
|
|
4178
|
+
if ((to == null || to === "" || to === ".") && activeRouteMatch) {
|
|
4179
|
+
let nakedIndex = hasNakedIndexQuery(path.search);
|
|
4180
|
+
if (activeRouteMatch.route.index && !nakedIndex) {
|
|
4181
|
+
// Add one when we're targeting an index route
|
|
4182
|
+
path.search = path.search ? path.search.replace(/^\?/, "?index&") : "?index";
|
|
4183
|
+
} else if (!activeRouteMatch.route.index && nakedIndex) {
|
|
4184
|
+
// Remove existing ones when we're not
|
|
4185
|
+
let params = new URLSearchParams(path.search);
|
|
4186
|
+
let indexValues = params.getAll("index");
|
|
4187
|
+
params.delete("index");
|
|
4188
|
+
indexValues.filter(v => v).forEach(v => params.append("index", v));
|
|
4189
|
+
let qs = params.toString();
|
|
4190
|
+
path.search = qs ? "?" + qs : "";
|
|
4191
|
+
}
|
|
4204
4192
|
}
|
|
4205
4193
|
|
|
4206
4194
|
// If we're operating within a basename, prepend it to the pathname. If
|
|
@@ -4249,8 +4237,8 @@ function normalizeNavigateOptions(normalizeFormMethod, isFetcher, path, opts) {
|
|
|
4249
4237
|
}
|
|
4250
4238
|
let text = typeof opts.body === "string" ? opts.body : opts.body instanceof FormData || opts.body instanceof URLSearchParams ?
|
|
4251
4239
|
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#plain-text-form-data
|
|
4252
|
-
Array.from(opts.body.entries()).reduce((acc,
|
|
4253
|
-
let [name, value] =
|
|
4240
|
+
Array.from(opts.body.entries()).reduce((acc, _ref3) => {
|
|
4241
|
+
let [name, value] = _ref3;
|
|
4254
4242
|
return "" + acc + name + "=" + value + "\n";
|
|
4255
4243
|
}, "") : String(opts.body);
|
|
4256
4244
|
return {
|
|
@@ -4340,26 +4328,37 @@ function normalizeNavigateOptions(normalizeFormMethod, isFetcher, path, opts) {
|
|
|
4340
4328
|
};
|
|
4341
4329
|
}
|
|
4342
4330
|
|
|
4343
|
-
// Filter out all routes below any caught error as they aren't going to
|
|
4331
|
+
// Filter out all routes at/below any caught error as they aren't going to
|
|
4344
4332
|
// render so we don't need to load them
|
|
4345
|
-
function getLoaderMatchesUntilBoundary(matches, boundaryId) {
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4333
|
+
function getLoaderMatchesUntilBoundary(matches, boundaryId, includeBoundary) {
|
|
4334
|
+
if (includeBoundary === void 0) {
|
|
4335
|
+
includeBoundary = false;
|
|
4336
|
+
}
|
|
4337
|
+
let index = matches.findIndex(m => m.route.id === boundaryId);
|
|
4338
|
+
if (index >= 0) {
|
|
4339
|
+
return matches.slice(0, includeBoundary ? index + 1 : index);
|
|
4352
4340
|
}
|
|
4353
|
-
return
|
|
4341
|
+
return matches;
|
|
4354
4342
|
}
|
|
4355
|
-
function getMatchesToLoad(history, state, matches, submission, location,
|
|
4343
|
+
function getMatchesToLoad(history, state, matches, submission, location, initialHydration, skipActionErrorRevalidation, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, deletedFetchers, fetchLoadMatches, fetchRedirectIds, routesToUse, basename, pendingActionResult) {
|
|
4356
4344
|
let actionResult = pendingActionResult ? isErrorResult(pendingActionResult[1]) ? pendingActionResult[1].error : pendingActionResult[1].data : undefined;
|
|
4357
4345
|
let currentUrl = history.createURL(state.location);
|
|
4358
4346
|
let nextUrl = history.createURL(location);
|
|
4359
4347
|
|
|
4360
4348
|
// Pick navigation matches that are net-new or qualify for revalidation
|
|
4361
|
-
let
|
|
4362
|
-
|
|
4349
|
+
let boundaryMatches = matches;
|
|
4350
|
+
if (initialHydration && state.errors) {
|
|
4351
|
+
// On initial hydration, only consider matches up to _and including_ the boundary.
|
|
4352
|
+
// This is inclusive to handle cases where a server loader ran successfully,
|
|
4353
|
+
// a child server loader bubbled up to this route, but this route has
|
|
4354
|
+
// `clientLoader.hydrate` so we want to still run the `clientLoader` so that
|
|
4355
|
+
// we have a complete version of `loaderData`
|
|
4356
|
+
boundaryMatches = getLoaderMatchesUntilBoundary(matches, Object.keys(state.errors)[0], true);
|
|
4357
|
+
} else if (pendingActionResult && isErrorResult(pendingActionResult[1])) {
|
|
4358
|
+
// If an action threw an error, we call loaders up to, but not including the
|
|
4359
|
+
// boundary
|
|
4360
|
+
boundaryMatches = getLoaderMatchesUntilBoundary(matches, pendingActionResult[0]);
|
|
4361
|
+
}
|
|
4363
4362
|
|
|
4364
4363
|
// Don't revalidate loaders by default after action 4xx/5xx responses
|
|
4365
4364
|
// when the flag is enabled. They can still opt-into revalidation via
|
|
@@ -4377,13 +4376,8 @@ function getMatchesToLoad(history, state, matches, submission, location, isIniti
|
|
|
4377
4376
|
if (route.loader == null) {
|
|
4378
4377
|
return false;
|
|
4379
4378
|
}
|
|
4380
|
-
if (
|
|
4381
|
-
|
|
4382
|
-
return true;
|
|
4383
|
-
}
|
|
4384
|
-
return state.loaderData[route.id] === undefined && (
|
|
4385
|
-
// Don't re-run if the loader ran and threw an error
|
|
4386
|
-
!state.errors || state.errors[route.id] === undefined);
|
|
4379
|
+
if (initialHydration) {
|
|
4380
|
+
return shouldLoadRouteOnHydration(route, state.loaderData, state.errors);
|
|
4387
4381
|
}
|
|
4388
4382
|
|
|
4389
4383
|
// Always call the loader on new route instances and pending defer cancellations
|
|
@@ -4417,11 +4411,11 @@ function getMatchesToLoad(history, state, matches, submission, location, isIniti
|
|
|
4417
4411
|
let revalidatingFetchers = [];
|
|
4418
4412
|
fetchLoadMatches.forEach((f, key) => {
|
|
4419
4413
|
// Don't revalidate:
|
|
4420
|
-
// - on initial
|
|
4414
|
+
// - on initial hydration (shouldn't be any fetchers then anyway)
|
|
4421
4415
|
// - if fetcher won't be present in the subsequent render
|
|
4422
4416
|
// - no longer matches the URL (v7_fetcherPersist=false)
|
|
4423
4417
|
// - was unmounted but persisted due to v7_fetcherPersist=true
|
|
4424
|
-
if (
|
|
4418
|
+
if (initialHydration || !matches.some(m => m.route.id === f.routeId) || deletedFetchers.has(key)) {
|
|
4425
4419
|
return;
|
|
4426
4420
|
}
|
|
4427
4421
|
let fetcherMatches = matchRoutes(routesToUse, f.path, basename);
|
|
@@ -4487,6 +4481,32 @@ function getMatchesToLoad(history, state, matches, submission, location, isIniti
|
|
|
4487
4481
|
});
|
|
4488
4482
|
return [navigationMatches, revalidatingFetchers];
|
|
4489
4483
|
}
|
|
4484
|
+
function shouldLoadRouteOnHydration(route, loaderData, errors) {
|
|
4485
|
+
// We dunno if we have a loader - gotta find out!
|
|
4486
|
+
if (route.lazy) {
|
|
4487
|
+
return true;
|
|
4488
|
+
}
|
|
4489
|
+
|
|
4490
|
+
// No loader, nothing to initialize
|
|
4491
|
+
if (!route.loader) {
|
|
4492
|
+
return false;
|
|
4493
|
+
}
|
|
4494
|
+
let hasData = loaderData != null && loaderData[route.id] !== undefined;
|
|
4495
|
+
let hasError = errors != null && errors[route.id] !== undefined;
|
|
4496
|
+
|
|
4497
|
+
// Don't run if we error'd during SSR
|
|
4498
|
+
if (!hasData && hasError) {
|
|
4499
|
+
return false;
|
|
4500
|
+
}
|
|
4501
|
+
|
|
4502
|
+
// Explicitly opting-in to running on hydration
|
|
4503
|
+
if (typeof route.loader === "function" && route.loader.hydrate === true) {
|
|
4504
|
+
return true;
|
|
4505
|
+
}
|
|
4506
|
+
|
|
4507
|
+
// Otherwise, run if we're not yet initialized with anything
|
|
4508
|
+
return !hasData && !hasError;
|
|
4509
|
+
}
|
|
4490
4510
|
function isNewLoader(currentLoaderData, currentMatch, match) {
|
|
4491
4511
|
let isNew =
|
|
4492
4512
|
// [a] -> [a, b]
|
|
@@ -4520,34 +4540,6 @@ function shouldRevalidateLoader(loaderMatch, arg) {
|
|
|
4520
4540
|
}
|
|
4521
4541
|
return arg.defaultShouldRevalidate;
|
|
4522
4542
|
}
|
|
4523
|
-
|
|
4524
|
-
/**
|
|
4525
|
-
* Idempotent utility to execute patchRoutesOnNavigation() to lazily load route
|
|
4526
|
-
* definitions and update the routes/routeManifest
|
|
4527
|
-
*/
|
|
4528
|
-
async function loadLazyRouteChildren(patchRoutesOnNavigationImpl, path, matches, routes, manifest, mapRouteProperties, pendingRouteChildren, signal) {
|
|
4529
|
-
let key = [path, ...matches.map(m => m.route.id)].join("-");
|
|
4530
|
-
try {
|
|
4531
|
-
let pending = pendingRouteChildren.get(key);
|
|
4532
|
-
if (!pending) {
|
|
4533
|
-
pending = patchRoutesOnNavigationImpl({
|
|
4534
|
-
path,
|
|
4535
|
-
matches,
|
|
4536
|
-
patch: (routeId, children) => {
|
|
4537
|
-
if (!signal.aborted) {
|
|
4538
|
-
patchRoutesImpl(routeId, children, routes, manifest, mapRouteProperties);
|
|
4539
|
-
}
|
|
4540
|
-
}
|
|
4541
|
-
});
|
|
4542
|
-
pendingRouteChildren.set(key, pending);
|
|
4543
|
-
}
|
|
4544
|
-
if (pending && isPromise(pending)) {
|
|
4545
|
-
await pending;
|
|
4546
|
-
}
|
|
4547
|
-
} finally {
|
|
4548
|
-
pendingRouteChildren.delete(key);
|
|
4549
|
-
}
|
|
4550
|
-
}
|
|
4551
4543
|
function patchRoutesImpl(routeId, children, routesToUse, manifest, mapRouteProperties) {
|
|
4552
4544
|
var _childrenToPatch;
|
|
4553
4545
|
let childrenToPatch;
|
|
@@ -4565,10 +4557,34 @@ function patchRoutesImpl(routeId, children, routesToUse, manifest, mapRoutePrope
|
|
|
4565
4557
|
// Don't patch in routes we already know about so that `patch` is idempotent
|
|
4566
4558
|
// to simplify user-land code. This is useful because we re-call the
|
|
4567
4559
|
// `patchRoutesOnNavigation` function for matched routes with params.
|
|
4568
|
-
let uniqueChildren = children.filter(
|
|
4560
|
+
let uniqueChildren = children.filter(newRoute => !childrenToPatch.some(existingRoute => isSameRoute(newRoute, existingRoute)));
|
|
4569
4561
|
let newRoutes = convertRoutesToDataRoutes(uniqueChildren, mapRouteProperties, [routeId || "_", "patch", String(((_childrenToPatch = childrenToPatch) == null ? void 0 : _childrenToPatch.length) || "0")], manifest);
|
|
4570
4562
|
childrenToPatch.push(...newRoutes);
|
|
4571
4563
|
}
|
|
4564
|
+
function isSameRoute(newRoute, existingRoute) {
|
|
4565
|
+
// Most optimal check is by id
|
|
4566
|
+
if ("id" in newRoute && "id" in existingRoute && newRoute.id === existingRoute.id) {
|
|
4567
|
+
return true;
|
|
4568
|
+
}
|
|
4569
|
+
|
|
4570
|
+
// Second is by pathing differences
|
|
4571
|
+
if (!(newRoute.index === existingRoute.index && newRoute.path === existingRoute.path && newRoute.caseSensitive === existingRoute.caseSensitive)) {
|
|
4572
|
+
return false;
|
|
4573
|
+
}
|
|
4574
|
+
|
|
4575
|
+
// Pathless layout routes are trickier since we need to check children.
|
|
4576
|
+
// If they have no children then they're the same as far as we can tell
|
|
4577
|
+
if ((!newRoute.children || newRoute.children.length === 0) && (!existingRoute.children || existingRoute.children.length === 0)) {
|
|
4578
|
+
return true;
|
|
4579
|
+
}
|
|
4580
|
+
|
|
4581
|
+
// Otherwise, we look to see if every child in the new route is already
|
|
4582
|
+
// represented in the existing route's children
|
|
4583
|
+
return newRoute.children.every((aChild, i) => {
|
|
4584
|
+
var _existingRoute$childr;
|
|
4585
|
+
return (_existingRoute$childr = existingRoute.children) == null ? void 0 : _existingRoute$childr.some(bChild => isSameRoute(aChild, bChild));
|
|
4586
|
+
});
|
|
4587
|
+
}
|
|
4572
4588
|
|
|
4573
4589
|
/**
|
|
4574
4590
|
* Execute route.lazy() methods to lazily load route modules (loader, action,
|
|
@@ -4624,10 +4640,10 @@ async function loadLazyRouteModule(route, mapRouteProperties, manifest) {
|
|
|
4624
4640
|
}
|
|
4625
4641
|
|
|
4626
4642
|
// Default implementation of `dataStrategy` which fetches all loaders in parallel
|
|
4627
|
-
async function defaultDataStrategy(
|
|
4643
|
+
async function defaultDataStrategy(_ref4) {
|
|
4628
4644
|
let {
|
|
4629
4645
|
matches
|
|
4630
|
-
} =
|
|
4646
|
+
} = _ref4;
|
|
4631
4647
|
let matchesToLoad = matches.filter(m => m.shouldLoad);
|
|
4632
4648
|
let results = await Promise.all(matchesToLoad.map(m => m.resolve()));
|
|
4633
4649
|
return results.reduce((acc, result, i) => Object.assign(acc, {
|
|
@@ -5041,7 +5057,7 @@ function processRouteLoaderData(matches, results, pendingActionResult, activeDef
|
|
|
5041
5057
|
loaderHeaders
|
|
5042
5058
|
};
|
|
5043
5059
|
}
|
|
5044
|
-
function processLoaderData(state, matches,
|
|
5060
|
+
function processLoaderData(state, matches, results, pendingActionResult, revalidatingFetchers, fetcherResults, activeDeferreds) {
|
|
5045
5061
|
let {
|
|
5046
5062
|
loaderData,
|
|
5047
5063
|
errors
|
|
@@ -5156,9 +5172,7 @@ function getInternalRouterError(status, _temp5) {
|
|
|
5156
5172
|
let errorMessage = "Unknown @remix-run/router error";
|
|
5157
5173
|
if (status === 400) {
|
|
5158
5174
|
statusText = "Bad Request";
|
|
5159
|
-
if (
|
|
5160
|
-
errorMessage = "Unable to match URL \"" + pathname + "\" - the `patchRoutesOnNavigation()` " + ("function threw the following error:\n" + message);
|
|
5161
|
-
} else if (method && pathname && routeId) {
|
|
5175
|
+
if (method && pathname && routeId) {
|
|
5162
5176
|
errorMessage = "You made a " + method + " request to \"" + pathname + "\" but " + ("did not provide a `loader` for route \"" + routeId + "\", ") + "so there is no way to handle the request.";
|
|
5163
5177
|
} else if (type === "defer-action") {
|
|
5164
5178
|
errorMessage = "defer() is not supported in actions";
|
|
@@ -5220,9 +5234,6 @@ function isHashChangeOnly(a, b) {
|
|
|
5220
5234
|
// /page#hash -> /page
|
|
5221
5235
|
return false;
|
|
5222
5236
|
}
|
|
5223
|
-
function isPromise(val) {
|
|
5224
|
-
return typeof val === "object" && val != null && "then" in val;
|
|
5225
|
-
}
|
|
5226
5237
|
function isDataStrategyResult(result) {
|
|
5227
5238
|
return result != null && typeof result === "object" && "type" in result && "result" in result && (result.type === ResultType.data || result.type === ResultType.error);
|
|
5228
5239
|
}
|