react-router 8.4.0 → 8.5.1
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 +94 -1
- package/dist/development/dom-export.d.ts +2 -1
- package/dist/development/dom-export.js +1 -1
- package/dist/development/index-react-server-client.js +2 -2
- package/dist/development/index-react-server.d.ts +237 -165
- package/dist/development/index-react-server.js +69 -33
- package/dist/development/index.d.ts +9 -8
- package/dist/development/index.js +5 -4
- package/dist/development/lib/actions.js +1 -1
- package/dist/development/lib/await.js +58 -0
- package/dist/development/lib/components.d.ts +41 -5
- package/dist/development/lib/components.js +82 -5
- package/dist/development/lib/context.d.ts +8 -3
- package/dist/development/lib/context.js +1 -1
- package/dist/development/lib/dom/dom.d.ts +3 -0
- package/dist/development/lib/dom/dom.js +1 -1
- package/dist/development/lib/dom/lib.d.ts +34 -9
- package/dist/development/lib/dom/lib.js +17 -6
- package/dist/development/lib/dom/server.js +2 -2
- package/dist/development/lib/dom/ssr/components.js +12 -9
- package/dist/development/lib/dom/ssr/data.js +1 -1
- package/dist/development/lib/dom/ssr/entry.d.ts +9 -2
- package/dist/development/lib/dom/ssr/errorBoundaries.js +1 -1
- package/dist/development/lib/dom/ssr/fallback.js +1 -1
- package/dist/development/lib/dom/ssr/fog-of-war.d.ts +3 -2
- package/dist/development/lib/dom/ssr/fog-of-war.js +25 -13
- package/dist/development/lib/dom/ssr/hydration.js +1 -1
- package/dist/development/lib/dom/ssr/invariant.js +1 -1
- package/dist/development/lib/dom/ssr/links.js +1 -1
- package/dist/development/lib/dom/ssr/markup.js +1 -1
- package/dist/development/lib/dom/ssr/route-discovery.d.ts +120 -0
- package/dist/development/lib/dom/ssr/route-discovery.js +415 -0
- package/dist/development/lib/dom/ssr/routeModules.js +1 -1
- package/dist/development/lib/dom/ssr/routes-test-stub.js +2 -2
- package/dist/development/lib/dom/ssr/routes.d.ts +2 -2
- package/dist/development/lib/dom/ssr/routes.js +8 -8
- package/dist/development/lib/dom/ssr/server.js +3 -1
- package/dist/development/lib/dom/ssr/single-fetch.d.ts +28 -2
- package/dist/development/lib/dom/ssr/single-fetch.js +73 -55
- package/dist/development/lib/dom-export/dom-router-provider.js +1 -1
- package/dist/development/lib/dom-export/hydrated-router.d.ts +28 -0
- package/dist/development/lib/dom-export/hydrated-router.js +32 -12
- package/dist/development/lib/errors.js +1 -1
- package/dist/development/lib/hooks.d.ts +3 -6
- package/dist/development/lib/hooks.js +8 -9
- package/dist/development/lib/href.js +1 -1
- package/dist/development/lib/router/history.js +1 -1
- package/dist/development/lib/router/instrumentation.js +1 -1
- package/dist/development/lib/router/matcher-route-pattern.js +1 -1
- package/dist/development/lib/router/matcher-route-pattern.preload.js +1 -1
- package/dist/development/lib/router/matcher.js +6 -1
- package/dist/development/lib/router/navigation.js +1 -1
- package/dist/development/lib/router/router.d.ts +8 -0
- package/dist/development/lib/router/router.js +213 -91
- package/dist/development/lib/router/url.js +1 -1
- package/dist/development/lib/router/utils.d.ts +31 -4
- package/dist/development/lib/router/utils.js +4 -3
- package/dist/development/lib/rsc/browser.js +4 -4
- package/dist/development/lib/rsc/errorBoundaries.js +1 -1
- package/dist/development/lib/rsc/html-stream/browser.js +1 -1
- package/dist/development/lib/rsc/html-stream/server.js +24 -12
- package/dist/development/lib/rsc/route-modules.js +1 -1
- package/dist/development/lib/rsc/server.rsc.d.ts +3 -2
- package/dist/development/lib/rsc/server.ssr.js +1 -1
- package/dist/development/lib/server-runtime/build.d.ts +14 -0
- package/dist/development/lib/server-runtime/cookies.js +1 -1
- package/dist/development/lib/server-runtime/crypto.js +1 -1
- package/dist/development/lib/server-runtime/data.js +1 -1
- package/dist/development/lib/server-runtime/dev.js +1 -1
- package/dist/development/lib/server-runtime/entry.js +1 -1
- package/dist/development/lib/server-runtime/errors.js +1 -1
- package/dist/development/lib/server-runtime/headers.js +1 -1
- package/dist/development/lib/server-runtime/invariant.js +1 -1
- package/dist/development/lib/server-runtime/mode.js +1 -1
- package/dist/development/lib/server-runtime/routeMatching.js +1 -1
- package/dist/development/lib/server-runtime/routes.d.ts +1 -1
- package/dist/development/lib/server-runtime/routes.js +1 -1
- package/dist/development/lib/server-runtime/server.js +24 -8
- package/dist/development/lib/server-runtime/serverHandoff.d.ts +17 -0
- package/dist/development/lib/server-runtime/serverHandoff.js +1 -1
- package/dist/development/lib/server-runtime/sessions/cookieStorage.js +1 -1
- package/dist/development/lib/server-runtime/sessions/memoryStorage.js +1 -1
- package/dist/development/lib/server-runtime/sessions.js +2 -2
- package/dist/development/lib/server-runtime/single-fetch.js +1 -1
- package/dist/development/lib/server-runtime/urls.js +1 -1
- package/dist/development/lib/server-runtime/warnings.js +1 -1
- package/dist/development/lib/types/internal.js +1 -1
- package/dist/development/lib/types/route-data.d.ts +2 -2
- package/dist/development/lib/types/route-module-annotations.d.ts +1 -1
- package/dist/development/route-pattern.js +1 -1
- package/dist/development/vendor/turbo-stream-v2/flatten.js +1 -1
- package/dist/development/vendor/turbo-stream-v2/turbo-stream.js +1 -1
- package/dist/development/vendor/turbo-stream-v2/unflatten.js +23 -3
- package/dist/development/vendor/turbo-stream-v2/utils.js +1 -1
- package/dist/production/dom-export.d.ts +2 -1
- package/dist/production/dom-export.js +1 -1
- package/dist/production/index-react-server-client.js +2 -2
- package/dist/production/index-react-server.d.ts +237 -165
- package/dist/production/index-react-server.js +69 -33
- package/dist/production/index.d.ts +9 -8
- package/dist/production/index.js +5 -4
- package/dist/production/lib/actions.js +1 -1
- package/dist/production/lib/await.js +58 -0
- package/dist/production/lib/components.d.ts +41 -5
- package/dist/production/lib/components.js +82 -5
- package/dist/production/lib/context.d.ts +8 -3
- package/dist/production/lib/context.js +1 -1
- package/dist/production/lib/dom/dom.d.ts +3 -0
- package/dist/production/lib/dom/dom.js +1 -1
- package/dist/production/lib/dom/lib.d.ts +34 -9
- package/dist/production/lib/dom/lib.js +17 -6
- package/dist/production/lib/dom/server.js +2 -2
- package/dist/production/lib/dom/ssr/components.js +12 -9
- package/dist/production/lib/dom/ssr/data.js +1 -1
- package/dist/production/lib/dom/ssr/entry.d.ts +9 -2
- package/dist/production/lib/dom/ssr/errorBoundaries.js +1 -1
- package/dist/production/lib/dom/ssr/fallback.js +1 -1
- package/dist/production/lib/dom/ssr/fog-of-war.d.ts +3 -2
- package/dist/production/lib/dom/ssr/fog-of-war.js +25 -13
- package/dist/production/lib/dom/ssr/hydration.js +1 -1
- package/dist/production/lib/dom/ssr/invariant.js +1 -1
- package/dist/production/lib/dom/ssr/links.js +1 -1
- package/dist/production/lib/dom/ssr/markup.js +1 -1
- package/dist/production/lib/dom/ssr/route-discovery.d.ts +120 -0
- package/dist/production/lib/dom/ssr/route-discovery.js +415 -0
- package/dist/production/lib/dom/ssr/routeModules.js +1 -1
- package/dist/production/lib/dom/ssr/routes-test-stub.js +2 -2
- package/dist/production/lib/dom/ssr/routes.d.ts +2 -2
- package/dist/production/lib/dom/ssr/routes.js +8 -8
- package/dist/production/lib/dom/ssr/server.js +3 -1
- package/dist/production/lib/dom/ssr/single-fetch.d.ts +28 -2
- package/dist/production/lib/dom/ssr/single-fetch.js +73 -55
- package/dist/production/lib/dom-export/dom-router-provider.js +1 -1
- package/dist/production/lib/dom-export/hydrated-router.d.ts +28 -0
- package/dist/production/lib/dom-export/hydrated-router.js +32 -12
- package/dist/production/lib/errors.js +1 -1
- package/dist/production/lib/hooks.d.ts +3 -6
- package/dist/production/lib/hooks.js +7 -8
- package/dist/production/lib/href.js +1 -1
- package/dist/production/lib/router/history.js +1 -1
- package/dist/production/lib/router/instrumentation.js +1 -1
- package/dist/production/lib/router/matcher-route-pattern.js +1 -1
- package/dist/production/lib/router/matcher-route-pattern.preload.js +1 -1
- package/dist/production/lib/router/matcher.js +6 -1
- package/dist/production/lib/router/navigation.js +1 -1
- package/dist/production/lib/router/router.d.ts +8 -0
- package/dist/production/lib/router/router.js +213 -91
- package/dist/production/lib/router/url.js +1 -1
- package/dist/production/lib/router/utils.d.ts +31 -4
- package/dist/production/lib/router/utils.js +4 -3
- package/dist/production/lib/rsc/browser.js +4 -4
- package/dist/production/lib/rsc/errorBoundaries.js +1 -1
- package/dist/production/lib/rsc/html-stream/browser.js +1 -1
- package/dist/production/lib/rsc/html-stream/server.js +24 -12
- package/dist/production/lib/rsc/route-modules.js +1 -1
- package/dist/production/lib/rsc/server.rsc.d.ts +3 -2
- package/dist/production/lib/rsc/server.ssr.js +1 -1
- package/dist/production/lib/server-runtime/build.d.ts +14 -0
- package/dist/production/lib/server-runtime/cookies.js +1 -1
- package/dist/production/lib/server-runtime/crypto.js +1 -1
- package/dist/production/lib/server-runtime/data.js +1 -1
- package/dist/production/lib/server-runtime/dev.js +1 -1
- package/dist/production/lib/server-runtime/entry.js +1 -1
- package/dist/production/lib/server-runtime/errors.js +1 -1
- package/dist/production/lib/server-runtime/headers.js +1 -1
- package/dist/production/lib/server-runtime/invariant.js +1 -1
- package/dist/production/lib/server-runtime/mode.js +1 -1
- package/dist/production/lib/server-runtime/routeMatching.js +1 -1
- package/dist/production/lib/server-runtime/routes.d.ts +1 -1
- package/dist/production/lib/server-runtime/routes.js +1 -1
- package/dist/production/lib/server-runtime/server.js +24 -8
- package/dist/production/lib/server-runtime/serverHandoff.d.ts +17 -0
- package/dist/production/lib/server-runtime/serverHandoff.js +1 -1
- package/dist/production/lib/server-runtime/sessions/cookieStorage.js +1 -1
- package/dist/production/lib/server-runtime/sessions/memoryStorage.js +1 -1
- package/dist/production/lib/server-runtime/sessions.js +2 -2
- package/dist/production/lib/server-runtime/single-fetch.js +1 -1
- package/dist/production/lib/server-runtime/urls.js +1 -1
- package/dist/production/lib/server-runtime/warnings.js +1 -1
- package/dist/production/lib/types/internal.js +1 -1
- package/dist/production/lib/types/route-data.d.ts +2 -2
- package/dist/production/lib/types/route-module-annotations.d.ts +1 -1
- package/dist/production/route-pattern.js +1 -1
- package/dist/production/vendor/turbo-stream-v2/flatten.js +1 -1
- package/dist/production/vendor/turbo-stream-v2/turbo-stream.js +1 -1
- package/dist/production/vendor/turbo-stream-v2/unflatten.js +23 -3
- package/dist/production/vendor/turbo-stream-v2/utils.js +1 -1
- package/docs/explanation/backend-for-frontend.md +0 -3
- package/docs/explanation/code-splitting.md +0 -3
- package/docs/explanation/concurrency.md +0 -3
- package/docs/explanation/hot-module-replacement.md +0 -3
- package/docs/explanation/lazy-route-discovery.md +4 -3
- package/docs/explanation/progressive-enhancement.md +0 -3
- package/docs/explanation/race-conditions.md +0 -3
- package/docs/explanation/react-transitions.md +0 -3
- package/docs/explanation/sessions-and-cookies.md +109 -5
- package/docs/explanation/state-management.md +0 -3
- package/docs/explanation/styling.md +0 -3
- package/docs/explanation/type-safety.md +0 -3
- package/docs/how-to/accessibility.md +0 -6
- package/docs/how-to/client-data.md +0 -3
- package/docs/how-to/custom-fetch.md +218 -0
- package/docs/how-to/data-strategy.md +23 -4
- package/docs/how-to/error-boundary.md +0 -3
- package/docs/how-to/error-reporting.md +0 -3
- package/docs/how-to/fetchers.md +0 -3
- package/docs/how-to/file-route-conventions.md +0 -3
- package/docs/how-to/file-uploads.md +0 -3
- package/docs/how-to/form-validation.md +0 -3
- package/docs/how-to/headers.md +0 -3
- package/docs/how-to/instrumentation.md +0 -3
- package/docs/how-to/middleware.md +7 -3
- package/docs/how-to/navigation-blocking.md +0 -3
- package/docs/how-to/optimize-revalidation.md +2 -5
- package/docs/how-to/pre-rendering.md +23 -4
- package/docs/how-to/presets.md +0 -3
- package/docs/how-to/react-server-components.md +0 -3
- package/docs/how-to/resource-routes.md +0 -3
- package/docs/how-to/route-discovery.md +147 -0
- package/docs/how-to/route-module-type-safety.md +0 -3
- package/docs/how-to/security.md +0 -3
- package/docs/how-to/server-bundles.md +0 -3
- package/docs/how-to/spa.md +2 -3
- package/docs/how-to/status.md +0 -3
- package/docs/how-to/suspense.md +22 -6
- package/docs/how-to/using-handle.md +0 -3
- package/docs/how-to/view-transitions.md +79 -15
- package/docs/start/framework/data-loading.md +9 -0
- package/docs/start/framework/navigating.md +5 -9
- package/docs/start/framework/rendering.md +37 -0
- package/docs/upgrading/future.md +0 -12
- package/docs/upgrading/v7.md +3 -33
- package/package.json +9 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* react-router v8.
|
|
2
|
+
* react-router v8.5.1
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { PROTOCOL_RELATIVE_URL_REGEX, normalizeProtocolRelativeUrl } from "./url.js";
|
|
12
12
|
import { createBrowserURLImpl, createLocation, createPath, invariant, parsePath, warning } from "./history.js";
|
|
13
|
-
import { ErrorResponseImpl, RouterContextProvider, convertRouteMatchToUiMatch, convertRoutesToDataRoutes, createDataFunctionUrl, getPathContributingMatches, getResolveToMatches, getRoutePattern, isAbsoluteUrl, isRouteErrorResponse, isUnsupportedLazyRouteFunctionKey, isUnsupportedLazyRouteObjectKey, prependBasename, removeDoubleSlashes, resolveTo, stripBasename } from "./utils.js";
|
|
13
|
+
import { DiscoveryCancelledError, ErrorResponseImpl, RouterContextProvider, convertRouteMatchToUiMatch, convertRoutesToDataRoutes, createDataFunctionUrl, getPathContributingMatches, getResolveToMatches, getRoutePattern, isAbsoluteUrl, isRouteErrorResponse, isUnsupportedLazyRouteFunctionKey, isUnsupportedLazyRouteObjectKey, prependBasename, removeDoubleSlashes, resolveTo, stripBasename } from "./utils.js";
|
|
14
14
|
import { consumeInstrumentationClientResultMetaReceiver, getRouteInstrumentationUpdates, instrumentClientSideRouter } from "./instrumentation.js";
|
|
15
15
|
import { V6RegExMatcher } from "./matcher.js";
|
|
16
16
|
import { getRoutePatternMatcher } from "./matcher-route-pattern.preload.js";
|
|
@@ -114,6 +114,7 @@ var DataRoutes = class {
|
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
116
|
};
|
|
117
|
+
const clientErrors = /* @__PURE__ */ new WeakMap();
|
|
117
118
|
/**
|
|
118
119
|
* Create a router and listen to history POP navigations
|
|
119
120
|
*/
|
|
@@ -142,7 +143,6 @@ function createRouter(init) {
|
|
|
142
143
|
let dataStrategyImpl = init.dataStrategy || defaultDataStrategyWithMiddleware;
|
|
143
144
|
let unlistenHistory = null;
|
|
144
145
|
let subscribers = /* @__PURE__ */ new Set();
|
|
145
|
-
let bufferedInitialStateUpdate = null;
|
|
146
146
|
let savedScrollPositions = null;
|
|
147
147
|
let getScrollRestorationKey = null;
|
|
148
148
|
let getScrollPosition = null;
|
|
@@ -213,6 +213,8 @@ function createRouter(init) {
|
|
|
213
213
|
blockers: /* @__PURE__ */ new Map()
|
|
214
214
|
};
|
|
215
215
|
let pendingAction = "POP";
|
|
216
|
+
let pendingPopstateDelta = 0;
|
|
217
|
+
let pendingDiscoveryCancellation;
|
|
216
218
|
let pendingPopstateNavigationDfd = null;
|
|
217
219
|
let pendingPreventScrollReset = false;
|
|
218
220
|
let pendingNavigationController;
|
|
@@ -273,6 +275,7 @@ function createRouter(init) {
|
|
|
273
275
|
pendingPopstateNavigationDfd = null;
|
|
274
276
|
return;
|
|
275
277
|
}
|
|
278
|
+
if (future.unstable_customRouteDiscovery) pendingPopstateDelta += delta || 0;
|
|
276
279
|
return startNavigation(historyAction, location);
|
|
277
280
|
});
|
|
278
281
|
if (isBrowser) {
|
|
@@ -294,19 +297,16 @@ function createRouter(init) {
|
|
|
294
297
|
}
|
|
295
298
|
function subscribe(fn) {
|
|
296
299
|
subscribers.add(fn);
|
|
297
|
-
if (bufferedInitialStateUpdate) {
|
|
298
|
-
let { newErrors } = bufferedInitialStateUpdate;
|
|
299
|
-
bufferedInitialStateUpdate = null;
|
|
300
|
-
fn(state, {
|
|
301
|
-
deletedFetchers: [],
|
|
302
|
-
newErrors,
|
|
303
|
-
viewTransitionOpts: void 0,
|
|
304
|
-
flushSync: false
|
|
305
|
-
});
|
|
306
|
-
}
|
|
307
300
|
return () => subscribers.delete(fn);
|
|
308
301
|
}
|
|
309
302
|
function updateState(newState, opts = {}) {
|
|
303
|
+
let newErrors = newState.errors ?? null;
|
|
304
|
+
let cachedErrors = newErrors ? clientErrors.get(newErrors) : void 0;
|
|
305
|
+
if (cachedErrors !== void 0) newErrors = cachedErrors;
|
|
306
|
+
if (newState.errors !== void 0 || newState.initialized) {
|
|
307
|
+
if (state.errors) clientErrors.delete(state.errors);
|
|
308
|
+
if (newState.errors) clientErrors.set(newState.errors, newErrors);
|
|
309
|
+
}
|
|
310
310
|
if (newState.matches) newState.matches = newState.matches.map((m) => {
|
|
311
311
|
let route = manifest[m.route.id];
|
|
312
312
|
let matchRoute = m.route;
|
|
@@ -329,10 +329,9 @@ function createRouter(init) {
|
|
|
329
329
|
fetchersQueuedForDeletion.forEach((key) => {
|
|
330
330
|
if (!state.fetchers.has(key) && !fetchControllers.has(key)) unmountedFetchers.push(key);
|
|
331
331
|
});
|
|
332
|
-
if (subscribers.size === 0) bufferedInitialStateUpdate = { newErrors: newState.errors ?? null };
|
|
333
332
|
[...subscribers].forEach((subscriber) => subscriber(state, {
|
|
334
333
|
deletedFetchers: unmountedFetchers,
|
|
335
|
-
newErrors
|
|
334
|
+
newErrors,
|
|
336
335
|
viewTransitionOpts: opts.viewTransitionOpts,
|
|
337
336
|
flushSync: opts.flushSync === true
|
|
338
337
|
}));
|
|
@@ -397,17 +396,22 @@ function createRouter(init) {
|
|
|
397
396
|
viewTransitionOpts,
|
|
398
397
|
flushSync: flushSync === true
|
|
399
398
|
});
|
|
400
|
-
|
|
401
|
-
pendingPreventScrollReset = false;
|
|
402
|
-
pendingViewTransitionEnabled = false;
|
|
403
|
-
isUninterruptedRevalidation = false;
|
|
404
|
-
isRevalidationRequired = false;
|
|
399
|
+
resetPendingNavigation();
|
|
405
400
|
pendingPopstateNavigationDfd?.resolve();
|
|
406
401
|
pendingPopstateNavigationDfd = null;
|
|
407
402
|
pendingRevalidationDfd?.resolve();
|
|
408
403
|
pendingRevalidationDfd = null;
|
|
409
404
|
}
|
|
405
|
+
function resetPendingNavigation() {
|
|
406
|
+
pendingPopstateDelta = 0;
|
|
407
|
+
pendingAction = "POP";
|
|
408
|
+
pendingPreventScrollReset = false;
|
|
409
|
+
pendingViewTransitionEnabled = false;
|
|
410
|
+
isUninterruptedRevalidation = false;
|
|
411
|
+
isRevalidationRequired = fetchReloadIds.size > 0;
|
|
412
|
+
}
|
|
410
413
|
async function navigate(to, opts) {
|
|
414
|
+
if (pendingDiscoveryCancellation) await pendingDiscoveryCancellation;
|
|
411
415
|
pendingPopstateNavigationDfd?.resolve();
|
|
412
416
|
pendingPopstateNavigationDfd = null;
|
|
413
417
|
if (typeof to === "number") {
|
|
@@ -442,8 +446,9 @@ function createRouter(init) {
|
|
|
442
446
|
validateNavigationTarget(to == null ? init.history.createHref(state.location) : typeof to === "string" ? to : createPath(to), init.history.createHref(nextLocation.mask || nextLocation), init.history.createURL("/"), "reject");
|
|
443
447
|
let userReplace = opts && opts.replace != null ? opts.replace : void 0;
|
|
444
448
|
let historyAction = "PUSH";
|
|
449
|
+
let currentPath = state.location.pathname + state.location.search;
|
|
445
450
|
if (userReplace === true) historyAction = "REPLACE";
|
|
446
|
-
else if (userReplace === false) {} else if (submission != null && isMutationMethod(submission.formMethod) && submission.formAction ===
|
|
451
|
+
else if (userReplace === false) {} else if (submission != null && isMutationMethod(submission.formMethod) && (submission.formAction === currentPath || nextLocation.pathname + nextLocation.search === currentPath)) historyAction = "REPLACE";
|
|
447
452
|
let preventScrollReset = opts && "preventScrollReset" in opts ? opts.preventScrollReset === true : void 0;
|
|
448
453
|
let flushSync = (opts && opts.flushSync) === true;
|
|
449
454
|
let blockerKey = shouldBlockNavigation({
|
|
@@ -484,22 +489,28 @@ function createRouter(init) {
|
|
|
484
489
|
});
|
|
485
490
|
}
|
|
486
491
|
function revalidate() {
|
|
492
|
+
if (pendingDiscoveryCancellation) return pendingDiscoveryCancellation.then(revalidate);
|
|
487
493
|
if (!pendingRevalidationDfd) pendingRevalidationDfd = createDeferred();
|
|
488
494
|
interruptActiveLoads();
|
|
489
495
|
updateState({ revalidation: "loading" });
|
|
490
496
|
let promise = pendingRevalidationDfd.promise;
|
|
491
497
|
if (state.navigation.state === "submitting") return promise;
|
|
492
498
|
if (state.navigation.state === "idle") {
|
|
493
|
-
startNavigation(state.historyAction, state.location, {
|
|
499
|
+
startNavigation(state.historyAction, state.location, {
|
|
500
|
+
startUninterruptedRevalidation: true,
|
|
501
|
+
dataStrategyInitiator: "revalidation"
|
|
502
|
+
});
|
|
494
503
|
return promise;
|
|
495
504
|
}
|
|
496
505
|
startNavigation(pendingAction || state.historyAction, state.navigation.location, {
|
|
497
506
|
overrideNavigation: state.navigation,
|
|
507
|
+
dataStrategyInitiator: "revalidation",
|
|
498
508
|
enableViewTransition: pendingViewTransitionEnabled === true
|
|
499
509
|
});
|
|
500
510
|
return promise;
|
|
501
511
|
}
|
|
502
512
|
async function startNavigation(historyAction, location, opts) {
|
|
513
|
+
if (pendingDiscoveryCancellation) await pendingDiscoveryCancellation;
|
|
503
514
|
pendingNavigationController && pendingNavigationController.abort();
|
|
504
515
|
pendingNavigationController = null;
|
|
505
516
|
pendingAction = historyAction;
|
|
@@ -535,6 +546,7 @@ function createRouter(init) {
|
|
|
535
546
|
} : void 0;
|
|
536
547
|
pendingNavigationController = new AbortController();
|
|
537
548
|
let request = createClientSideRequest(init.history, location, pendingNavigationController.signal, opts && opts.submission);
|
|
549
|
+
let dataStrategyInitiator = opts?.initialHydration ? "initialization" : opts?.dataStrategyInitiator ?? "navigation";
|
|
538
550
|
let scopedContext = init.getContext ? await init.getContext() : new RouterContextProvider();
|
|
539
551
|
let pendingActionResult;
|
|
540
552
|
if (opts && opts.pendingError) pendingActionResult = [findNearestBoundary(matches).route.id, {
|
|
@@ -542,7 +554,7 @@ function createRouter(init) {
|
|
|
542
554
|
error: opts.pendingError
|
|
543
555
|
}];
|
|
544
556
|
else if (opts && opts.submission && isMutationMethod(opts.submission.formMethod)) {
|
|
545
|
-
let actionResult = await handleAction(request, location, opts.submission, matches, historyAction, scopedContext, fogOfWar.active, opts && opts.initialHydration === true, {
|
|
557
|
+
let actionResult = await handleAction(request, dataStrategyInitiator, location, opts.submission, matches, historyAction, scopedContext, fogOfWar.active, opts && opts.initialHydration === true, {
|
|
546
558
|
replace: opts.replace,
|
|
547
559
|
flushSync
|
|
548
560
|
});
|
|
@@ -566,7 +578,7 @@ function createRouter(init) {
|
|
|
566
578
|
fogOfWar.active = false;
|
|
567
579
|
request = createClientSideRequest(init.history, request.url, request.signal);
|
|
568
580
|
}
|
|
569
|
-
let { shortCircuited, matches: updatedMatches, loaderData, errors, workingFetchers } = await handleLoaders(request, location, matches, historyAction, scopedContext, fogOfWar.active, loadingNavigation, opts && opts.submission, opts && opts.fetcherSubmission, opts && opts.replace, opts && opts.initialHydration === true, flushSync, pendingActionResult, opts && opts.callSiteDefaultShouldRevalidate);
|
|
581
|
+
let { shortCircuited, matches: updatedMatches, loaderData, errors, workingFetchers } = await handleLoaders(request, dataStrategyInitiator, location, matches, historyAction, scopedContext, fogOfWar.active, loadingNavigation, opts && opts.submission, opts && opts.fetcherSubmission, opts && opts.replace, opts && opts.initialHydration === true, flushSync, pendingActionResult, opts && opts.callSiteDefaultShouldRevalidate);
|
|
570
582
|
if (shortCircuited) return;
|
|
571
583
|
pendingNavigationController = null;
|
|
572
584
|
completeNavigation(location, {
|
|
@@ -577,13 +589,57 @@ function createRouter(init) {
|
|
|
577
589
|
...workingFetchers ? { fetchers: workingFetchers } : {}
|
|
578
590
|
});
|
|
579
591
|
}
|
|
580
|
-
|
|
581
|
-
|
|
592
|
+
function cancelDiscoveryNavigation() {
|
|
593
|
+
let cancellation = createDeferred();
|
|
594
|
+
pendingDiscoveryCancellation = cancellation.promise;
|
|
595
|
+
let delta = pendingPopstateDelta;
|
|
596
|
+
let popstateNavigationDfd = pendingPopstateNavigationDfd;
|
|
597
|
+
pendingPopstateNavigationDfd = null;
|
|
598
|
+
pendingNavigationController?.abort();
|
|
599
|
+
pendingNavigationController = null;
|
|
600
|
+
resetPendingNavigation();
|
|
601
|
+
pendingRevalidationDfd?.resolve();
|
|
602
|
+
pendingRevalidationDfd = null;
|
|
603
|
+
let blockers = new Map(state.blockers);
|
|
604
|
+
blockers.forEach((blocker, key) => {
|
|
605
|
+
if (blocker.state === "proceeding") blockers.set(key, IDLE_BLOCKER);
|
|
606
|
+
});
|
|
607
|
+
let fetchers = new Map(state.fetchers);
|
|
608
|
+
let didUpdateFetchers = markFetchRedirectsDone(fetchers);
|
|
609
|
+
fetchers.forEach((fetcher, key) => {
|
|
610
|
+
if (fetcher.state === "loading" && !fetchControllers.has(key)) {
|
|
611
|
+
fetchers.set(key, getDoneFetcher(fetcher.data));
|
|
612
|
+
didUpdateFetchers = true;
|
|
613
|
+
}
|
|
614
|
+
});
|
|
615
|
+
cancelledFetcherLoads.clear();
|
|
616
|
+
updateState({
|
|
617
|
+
navigation: IDLE_NAVIGATION,
|
|
618
|
+
revalidation: "idle",
|
|
619
|
+
blockers,
|
|
620
|
+
...didUpdateFetchers ? { fetchers } : {}
|
|
621
|
+
});
|
|
622
|
+
function finishCancellation() {
|
|
623
|
+
pendingDiscoveryCancellation = void 0;
|
|
624
|
+
popstateNavigationDfd?.resolve();
|
|
625
|
+
cancellation.resolve();
|
|
626
|
+
}
|
|
627
|
+
if (delta) {
|
|
628
|
+
unblockBlockerHistoryUpdate = finishCancellation;
|
|
629
|
+
init.history.go(-delta);
|
|
630
|
+
} else finishCancellation();
|
|
631
|
+
return cancellation.promise;
|
|
632
|
+
}
|
|
633
|
+
async function handleAction(request, dataStrategyInitiator, location, submission, matches, historyAction, scopedContext, isFogOfWar, initialHydration, opts = {}) {
|
|
634
|
+
if (!future.unstable_customRouteDiscovery) interruptActiveLoads();
|
|
582
635
|
updateState({ navigation: getSubmittingNavigation(location, matches, historyAction, submission) }, { flushSync: opts.flushSync === true });
|
|
583
636
|
if (isFogOfWar) {
|
|
584
637
|
let discoverResult = await discoverRoutes(matches, location.pathname, request.signal);
|
|
585
|
-
if (discoverResult.type === "aborted") return { shortCircuited: true };
|
|
586
|
-
else if (discoverResult.type === "
|
|
638
|
+
if (future.unstable_customRouteDiscovery && request.signal.aborted || discoverResult.type === "aborted") return { shortCircuited: true };
|
|
639
|
+
else if (discoverResult.type === "cancelled") {
|
|
640
|
+
await cancelDiscoveryNavigation();
|
|
641
|
+
return { shortCircuited: true };
|
|
642
|
+
} else if (discoverResult.type === "error") {
|
|
587
643
|
if (discoverResult.partialMatches.length === 0) {
|
|
588
644
|
let { matches, route } = getShortCircuitMatches(dataRoutes.activeRoutes);
|
|
589
645
|
return {
|
|
@@ -613,6 +669,7 @@ function createRouter(init) {
|
|
|
613
669
|
};
|
|
614
670
|
} else matches = discoverResult.matches;
|
|
615
671
|
}
|
|
672
|
+
if (future.unstable_customRouteDiscovery) interruptActiveLoads();
|
|
616
673
|
let result;
|
|
617
674
|
let actionMatch = getTargetMatch(matches, location);
|
|
618
675
|
if (!actionMatch.route.action && !actionMatch.route.lazy) result = {
|
|
@@ -624,7 +681,7 @@ function createRouter(init) {
|
|
|
624
681
|
})
|
|
625
682
|
};
|
|
626
683
|
else {
|
|
627
|
-
let results = await callDataStrategy(request, location, getTargetedDataStrategyMatches(mapRouteProperties, manifest, request, location, matches, actionMatch, initialHydration ? [] : hydrationRouteProperties, scopedContext), scopedContext, null);
|
|
684
|
+
let results = await callDataStrategy(request, location, getTargetedDataStrategyMatches(mapRouteProperties, manifest, request, location, matches, actionMatch, initialHydration ? [] : hydrationRouteProperties, scopedContext), scopedContext, null, dataStrategyInitiator, historyAction);
|
|
628
685
|
result = results[actionMatch.route.id];
|
|
629
686
|
if (!result) {
|
|
630
687
|
for (let match of matches) if (results[match.route.id]) {
|
|
@@ -638,7 +695,7 @@ function createRouter(init) {
|
|
|
638
695
|
let replace;
|
|
639
696
|
if (opts && opts.replace != null) replace = opts.replace;
|
|
640
697
|
else replace = normalizeRedirectLocation(result.response.headers.get("Location"), new URL(request.url), basename, init.history) === state.location.pathname + state.location.search;
|
|
641
|
-
await startRedirectNavigation(request, result, true, {
|
|
698
|
+
await startRedirectNavigation(request, result, true, dataStrategyInitiator, {
|
|
642
699
|
submission,
|
|
643
700
|
replace
|
|
644
701
|
});
|
|
@@ -661,7 +718,7 @@ function createRouter(init) {
|
|
|
661
718
|
pendingActionResult: [actionMatch.route.id, result]
|
|
662
719
|
};
|
|
663
720
|
}
|
|
664
|
-
async function handleLoaders(request, location, matches, historyAction, scopedContext, isFogOfWar, overrideNavigation, submission, fetcherSubmission, replace, initialHydration, flushSync, pendingActionResult, callSiteDefaultShouldRevalidate) {
|
|
721
|
+
async function handleLoaders(request, dataStrategyInitiator, location, matches, historyAction, scopedContext, isFogOfWar, overrideNavigation, submission, fetcherSubmission, replace, initialHydration, flushSync, pendingActionResult, callSiteDefaultShouldRevalidate) {
|
|
665
722
|
let loadingNavigation = overrideNavigation || getLoadingNavigation(location, matches, historyAction, submission);
|
|
666
723
|
let activeSubmission = submission || fetcherSubmission || getSubmissionFromNavigation(loadingNavigation);
|
|
667
724
|
let shouldUpdateNavigationState = !isUninterruptedRevalidation && !initialHydration;
|
|
@@ -674,8 +731,11 @@ function createRouter(init) {
|
|
|
674
731
|
}, { flushSync });
|
|
675
732
|
}
|
|
676
733
|
let discoverResult = await discoverRoutes(matches, location.pathname, request.signal);
|
|
677
|
-
if (discoverResult.type === "aborted") return { shortCircuited: true };
|
|
678
|
-
else if (discoverResult.type === "
|
|
734
|
+
if (future.unstable_customRouteDiscovery && request.signal.aborted || discoverResult.type === "aborted") return { shortCircuited: true };
|
|
735
|
+
else if (discoverResult.type === "cancelled") {
|
|
736
|
+
await cancelDiscoveryNavigation();
|
|
737
|
+
return { shortCircuited: true };
|
|
738
|
+
} else if (discoverResult.type === "error") {
|
|
679
739
|
if (discoverResult.partialMatches.length === 0) {
|
|
680
740
|
let { matches, route } = getShortCircuitMatches(dataRoutes.activeRoutes);
|
|
681
741
|
return {
|
|
@@ -697,7 +757,10 @@ function createRouter(init) {
|
|
|
697
757
|
loaderData: {},
|
|
698
758
|
errors: { [route.id]: error }
|
|
699
759
|
};
|
|
700
|
-
} else
|
|
760
|
+
} else {
|
|
761
|
+
matches = discoverResult.matches;
|
|
762
|
+
if (initialHydration && !request.signal.aborted) updateState({ matches });
|
|
763
|
+
}
|
|
701
764
|
}
|
|
702
765
|
let { dsMatches, revalidatingFetchers } = getMatchesToLoad(request, scopedContext, mapRouteProperties, manifest, init.history, state, matches, activeSubmission, location, initialHydration ? [] : hydrationRouteProperties, initialHydration === true, isRevalidationRequired, cancelledFetcherLoads, fetchersQueuedForDeletion, fetchLoadMatches, fetchRedirectIds, dataRouteMatcher, pendingActionResult, callSiteDefaultShouldRevalidate);
|
|
703
766
|
pendingNavigationLoadId = ++incrementingLoadId;
|
|
@@ -727,29 +790,37 @@ function createRouter(init) {
|
|
|
727
790
|
abortFetcher(rf.key);
|
|
728
791
|
if (rf.controller) fetchControllers.set(rf.key, rf.controller);
|
|
729
792
|
});
|
|
730
|
-
let abortPendingFetchRevalidations = () => revalidatingFetchers.forEach((
|
|
793
|
+
let abortPendingFetchRevalidations = () => revalidatingFetchers.forEach((rf) => {
|
|
794
|
+
if (fetchControllers.get(rf.key) === rf.controller) abortFetcher(rf.key);
|
|
795
|
+
});
|
|
731
796
|
if (pendingNavigationController) pendingNavigationController.signal.addEventListener("abort", abortPendingFetchRevalidations);
|
|
732
|
-
let { loaderResults, fetcherResults } = await callLoadersAndMaybeResolveData(dsMatches, revalidatingFetchers, request, location, scopedContext);
|
|
797
|
+
let { loaderResults, fetcherResults } = await callLoadersAndMaybeResolveData(dsMatches, revalidatingFetchers, request, location, scopedContext, dataStrategyInitiator, historyAction);
|
|
733
798
|
if (request.signal.aborted) return { shortCircuited: true };
|
|
734
799
|
if (pendingNavigationController) pendingNavigationController.signal.removeEventListener("abort", abortPendingFetchRevalidations);
|
|
735
|
-
revalidatingFetchers.forEach((rf) =>
|
|
800
|
+
revalidatingFetchers.forEach((rf) => {
|
|
801
|
+
if (fetchControllers.get(rf.key) === rf.controller) fetchControllers.delete(rf.key);
|
|
802
|
+
});
|
|
736
803
|
let redirect = findRedirect(loaderResults);
|
|
737
804
|
if (redirect) {
|
|
738
|
-
await startRedirectNavigation(request, redirect.result, true, { replace });
|
|
805
|
+
await startRedirectNavigation(request, redirect.result, true, dataStrategyInitiator, { replace });
|
|
739
806
|
return { shortCircuited: true };
|
|
740
807
|
}
|
|
741
808
|
redirect = findRedirect(fetcherResults);
|
|
742
809
|
if (redirect) {
|
|
743
810
|
fetchRedirectIds.add(redirect.key);
|
|
744
|
-
await startRedirectNavigation(request, redirect.result, true, { replace });
|
|
811
|
+
await startRedirectNavigation(request, redirect.result, true, dataStrategyInitiator, { replace });
|
|
745
812
|
return { shortCircuited: true };
|
|
746
813
|
}
|
|
747
814
|
let workingFetchers = new Map(state.fetchers);
|
|
748
815
|
let { loaderData, errors } = processLoaderData(state, matches, loaderResults, pendingActionResult, revalidatingFetchers, fetcherResults, workingFetchers);
|
|
749
|
-
if (initialHydration && state.errors)
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
816
|
+
if (initialHydration && state.errors) {
|
|
817
|
+
let newClientErrors = errors ?? null;
|
|
818
|
+
errors = {
|
|
819
|
+
...state.errors,
|
|
820
|
+
...errors
|
|
821
|
+
};
|
|
822
|
+
clientErrors.set(errors, newClientErrors);
|
|
823
|
+
}
|
|
753
824
|
let didUpdateFetcherRedirects = markFetchRedirectsDone(workingFetchers);
|
|
754
825
|
let didAbortFetchLoads = abortStaleFetchLoads(pendingNavigationLoadId, workingFetchers);
|
|
755
826
|
let shouldUpdateFetchers = didUpdateFetcherRedirects || didAbortFetchLoads || revalidatingFetchers.length > 0;
|
|
@@ -775,6 +846,7 @@ function createRouter(init) {
|
|
|
775
846
|
return workingFetchers;
|
|
776
847
|
}
|
|
777
848
|
async function fetch(key, routeId, href, opts) {
|
|
849
|
+
if (pendingDiscoveryCancellation) await pendingDiscoveryCancellation;
|
|
778
850
|
abortFetcher(key);
|
|
779
851
|
let flushSync = (opts && opts.flushSync) === true;
|
|
780
852
|
let instrumentationResultMetaReceiver = consumeInstrumentationClientResultMetaReceiver(router);
|
|
@@ -807,15 +879,22 @@ function createRouter(init) {
|
|
|
807
879
|
await handleFetcherLoader(key, loadMatch, matches, scopedContext, flushSync, preventScrollReset, submission);
|
|
808
880
|
}
|
|
809
881
|
async function handleFetcherAction(key, routeId, path, requestMatches, scopedContext, isFogOfWar, flushSync, preventScrollReset, submission, callSiteDefaultShouldRevalidate) {
|
|
810
|
-
interruptActiveLoads();
|
|
882
|
+
if (!future.unstable_customRouteDiscovery) interruptActiveLoads();
|
|
811
883
|
fetchLoadMatches.delete(key);
|
|
812
|
-
|
|
884
|
+
let existingFetcher = state.fetchers.get(key);
|
|
885
|
+
updateFetcherState(key, getSubmittingFetcher(submission, existingFetcher), { flushSync });
|
|
813
886
|
let abortController = new AbortController();
|
|
887
|
+
if (future.unstable_customRouteDiscovery) fetchControllers.set(key, abortController);
|
|
814
888
|
let fetchRequest = createClientSideRequest(init.history, path, abortController.signal, submission);
|
|
815
889
|
if (isFogOfWar) {
|
|
816
890
|
let discoverResult = await discoverRoutes(requestMatches, new URL(fetchRequest.url).pathname, fetchRequest.signal, key);
|
|
817
|
-
if (discoverResult.type === "aborted") return;
|
|
818
|
-
else if (discoverResult.type === "
|
|
891
|
+
if (future.unstable_customRouteDiscovery && fetchRequest.signal.aborted || discoverResult.type === "aborted") return;
|
|
892
|
+
else if (discoverResult.type === "cancelled") {
|
|
893
|
+
fetchControllers.delete(key);
|
|
894
|
+
fetchLoadMatches.delete(key);
|
|
895
|
+
updateFetcherState(key, getDoneFetcher(existingFetcher?.data), { flushSync });
|
|
896
|
+
return;
|
|
897
|
+
} else if (discoverResult.type === "error") {
|
|
819
898
|
setFetcherError(key, routeId, discoverResult.error, { flushSync });
|
|
820
899
|
return;
|
|
821
900
|
} else if (!discoverResult.matches) {
|
|
@@ -832,10 +911,11 @@ function createRouter(init) {
|
|
|
832
911
|
}), { flushSync });
|
|
833
912
|
return;
|
|
834
913
|
}
|
|
914
|
+
if (future.unstable_customRouteDiscovery) interruptActiveLoads();
|
|
835
915
|
fetchControllers.set(key, abortController);
|
|
836
916
|
let originatingLoadId = incrementingLoadId;
|
|
837
917
|
let fetchMatches = getTargetedDataStrategyMatches(mapRouteProperties, manifest, fetchRequest, path, requestMatches, match, hydrationRouteProperties, scopedContext);
|
|
838
|
-
let actionResults = await callDataStrategy(fetchRequest, path, fetchMatches, scopedContext, key);
|
|
918
|
+
let actionResults = await callDataStrategy(fetchRequest, path, fetchMatches, scopedContext, key, "fetcher");
|
|
839
919
|
let actionResult = actionResults[match.route.id];
|
|
840
920
|
if (!actionResult) {
|
|
841
921
|
for (let match of fetchMatches) if (actionResults[match.route.id]) {
|
|
@@ -848,30 +928,39 @@ function createRouter(init) {
|
|
|
848
928
|
return;
|
|
849
929
|
}
|
|
850
930
|
if (fetchersQueuedForDeletion.has(key)) {
|
|
851
|
-
if (
|
|
931
|
+
if (isErrorResult(actionResult)) {
|
|
852
932
|
updateFetcherState(key, getDoneFetcher(void 0));
|
|
853
933
|
return;
|
|
854
934
|
}
|
|
855
|
-
} else {
|
|
856
935
|
if (isRedirectResult(actionResult)) {
|
|
936
|
+
isRevalidationRequired = true;
|
|
937
|
+
actionResult = {
|
|
938
|
+
type: "data",
|
|
939
|
+
data: void 0
|
|
940
|
+
};
|
|
941
|
+
}
|
|
942
|
+
} else {
|
|
943
|
+
if (isRedirectResult(actionResult)) if (pendingNavigationLoadId > originatingLoadId) {
|
|
944
|
+
isRevalidationRequired = true;
|
|
945
|
+
actionResult = {
|
|
946
|
+
type: "data",
|
|
947
|
+
data: void 0
|
|
948
|
+
};
|
|
949
|
+
} else {
|
|
857
950
|
fetchControllers.delete(key);
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
return startRedirectNavigation(fetchRequest, actionResult, false, {
|
|
865
|
-
fetcherSubmission: submission,
|
|
866
|
-
preventScrollReset
|
|
867
|
-
});
|
|
868
|
-
}
|
|
951
|
+
fetchRedirectIds.add(key);
|
|
952
|
+
updateFetcherState(key, getLoadingFetcher(submission));
|
|
953
|
+
return startRedirectNavigation(fetchRequest, actionResult, false, "fetcher", {
|
|
954
|
+
fetcherSubmission: submission,
|
|
955
|
+
preventScrollReset
|
|
956
|
+
});
|
|
869
957
|
}
|
|
870
958
|
if (isErrorResult(actionResult)) {
|
|
871
959
|
setFetcherError(key, routeId, actionResult.error);
|
|
872
960
|
return;
|
|
873
961
|
}
|
|
874
962
|
}
|
|
963
|
+
isRevalidationRequired = true;
|
|
875
964
|
let nextLocation = state.navigation.location || state.location;
|
|
876
965
|
let revalidationRequest = createClientSideRequest(init.history, nextLocation, abortController.signal);
|
|
877
966
|
let matches = state.navigation.state !== "idle" ? dataRouteMatcher.match(state.navigation.location) : state.matches;
|
|
@@ -891,9 +980,11 @@ function createRouter(init) {
|
|
|
891
980
|
if (rf.controller) fetchControllers.set(staleKey, rf.controller);
|
|
892
981
|
});
|
|
893
982
|
updateState({ fetchers: workingFetchers });
|
|
894
|
-
let abortPendingFetchRevalidations = () => revalidatingFetchers.forEach((rf) =>
|
|
983
|
+
let abortPendingFetchRevalidations = () => revalidatingFetchers.forEach((rf) => {
|
|
984
|
+
if (fetchControllers.get(rf.key) === rf.controller) abortFetcher(rf.key);
|
|
985
|
+
});
|
|
895
986
|
abortController.signal.addEventListener("abort", abortPendingFetchRevalidations);
|
|
896
|
-
let { loaderResults, fetcherResults } = await callLoadersAndMaybeResolveData(dsMatches, revalidatingFetchers, revalidationRequest, nextLocation, scopedContext);
|
|
987
|
+
let { loaderResults, fetcherResults } = await callLoadersAndMaybeResolveData(dsMatches, revalidatingFetchers, revalidationRequest, nextLocation, scopedContext, "fetcher");
|
|
897
988
|
if (abortController.signal.aborted) {
|
|
898
989
|
if (fetchReloadIds.get(key) === loadId) fetchReloadIds.delete(key);
|
|
899
990
|
return;
|
|
@@ -901,7 +992,9 @@ function createRouter(init) {
|
|
|
901
992
|
abortController.signal.removeEventListener("abort", abortPendingFetchRevalidations);
|
|
902
993
|
fetchReloadIds.delete(key);
|
|
903
994
|
fetchControllers.delete(key);
|
|
904
|
-
revalidatingFetchers.forEach((r) =>
|
|
995
|
+
revalidatingFetchers.forEach((r) => {
|
|
996
|
+
if (fetchControllers.get(r.key) === r.controller) fetchControllers.delete(r.key);
|
|
997
|
+
});
|
|
905
998
|
let fetcherIsMounted = state.fetchers.has(key);
|
|
906
999
|
let getRedirectStateWithDoneFetcher = (s) => {
|
|
907
1000
|
if (!fetcherIsMounted) return s;
|
|
@@ -915,13 +1008,13 @@ function createRouter(init) {
|
|
|
915
1008
|
let redirect = findRedirect(loaderResults);
|
|
916
1009
|
if (redirect) {
|
|
917
1010
|
state = getRedirectStateWithDoneFetcher(state);
|
|
918
|
-
return startRedirectNavigation(revalidationRequest, redirect.result, false, { preventScrollReset });
|
|
1011
|
+
return startRedirectNavigation(revalidationRequest, redirect.result, false, "fetcher", { preventScrollReset });
|
|
919
1012
|
}
|
|
920
1013
|
redirect = findRedirect(fetcherResults);
|
|
921
1014
|
if (redirect) {
|
|
922
1015
|
fetchRedirectIds.add(redirect.key);
|
|
923
1016
|
state = getRedirectStateWithDoneFetcher(state);
|
|
924
|
-
return startRedirectNavigation(revalidationRequest, redirect.result, false, { preventScrollReset });
|
|
1017
|
+
return startRedirectNavigation(revalidationRequest, redirect.result, false, "fetcher", { preventScrollReset });
|
|
925
1018
|
}
|
|
926
1019
|
let finalFetchers = new Map(state.fetchers);
|
|
927
1020
|
if (fetcherIsMounted) finalFetchers.set(key, getDoneFetcher(actionResult.data));
|
|
@@ -930,6 +1023,7 @@ function createRouter(init) {
|
|
|
930
1023
|
if (state.navigation.state === "loading" && loadId > pendingNavigationLoadId) {
|
|
931
1024
|
invariant(pendingAction, "Expected pending action");
|
|
932
1025
|
pendingNavigationController && pendingNavigationController.abort();
|
|
1026
|
+
markFetchRedirectsDone(finalFetchers);
|
|
933
1027
|
completeNavigation(state.navigation.location, {
|
|
934
1028
|
matches,
|
|
935
1029
|
loaderData,
|
|
@@ -942,7 +1036,7 @@ function createRouter(init) {
|
|
|
942
1036
|
loaderData: mergeLoaderData(state.loaderData, loaderData, matches, errors),
|
|
943
1037
|
fetchers: finalFetchers
|
|
944
1038
|
});
|
|
945
|
-
isRevalidationRequired =
|
|
1039
|
+
isRevalidationRequired = fetchReloadIds.size > 0;
|
|
946
1040
|
}
|
|
947
1041
|
}
|
|
948
1042
|
async function handleFetcherLoader(key, loadMatch, matches, scopedContext, flushSync, preventScrollReset, submission) {
|
|
@@ -950,11 +1044,17 @@ function createRouter(init) {
|
|
|
950
1044
|
let existingFetcher = state.fetchers.get(key);
|
|
951
1045
|
updateFetcherState(key, getLoadingFetcher(submission, existingFetcher ? existingFetcher.data : void 0), { flushSync });
|
|
952
1046
|
let abortController = new AbortController();
|
|
1047
|
+
if (future.unstable_customRouteDiscovery) fetchControllers.set(key, abortController);
|
|
953
1048
|
let fetchRequest = createClientSideRequest(init.history, path, abortController.signal);
|
|
954
1049
|
if (loadMatch.isDiscovering) {
|
|
955
1050
|
let discoverResult = await discoverRoutes(matches, new URL(fetchRequest.url).pathname, fetchRequest.signal, key);
|
|
956
|
-
if (discoverResult.type === "aborted") return;
|
|
957
|
-
else if (discoverResult.type === "
|
|
1051
|
+
if (future.unstable_customRouteDiscovery && fetchRequest.signal.aborted || discoverResult.type === "aborted") return;
|
|
1052
|
+
else if (discoverResult.type === "cancelled") {
|
|
1053
|
+
fetchControllers.delete(key);
|
|
1054
|
+
fetchLoadMatches.delete(key);
|
|
1055
|
+
updateFetcherState(key, getDoneFetcher(existingFetcher?.data), { flushSync });
|
|
1056
|
+
return;
|
|
1057
|
+
} else if (discoverResult.type === "error") {
|
|
958
1058
|
setFetcherError(key, routeId, discoverResult.error, { flushSync });
|
|
959
1059
|
return;
|
|
960
1060
|
} else if (!discoverResult.matches) {
|
|
@@ -968,7 +1068,7 @@ function createRouter(init) {
|
|
|
968
1068
|
let match = getTargetMatch(matches, path);
|
|
969
1069
|
fetchControllers.set(key, abortController);
|
|
970
1070
|
let originatingLoadId = incrementingLoadId;
|
|
971
|
-
let results = await callDataStrategy(fetchRequest, path, getTargetedDataStrategyMatches(mapRouteProperties, manifest, fetchRequest, path, matches, match, hydrationRouteProperties, scopedContext), scopedContext, key);
|
|
1071
|
+
let results = await callDataStrategy(fetchRequest, path, getTargetedDataStrategyMatches(mapRouteProperties, manifest, fetchRequest, path, matches, match, hydrationRouteProperties, scopedContext), scopedContext, key, "fetcher");
|
|
972
1072
|
let result = results[match.route.id];
|
|
973
1073
|
if (!result) {
|
|
974
1074
|
for (let match of matches) if (results[match.route.id]) {
|
|
@@ -987,7 +1087,7 @@ function createRouter(init) {
|
|
|
987
1087
|
return;
|
|
988
1088
|
} else {
|
|
989
1089
|
fetchRedirectIds.add(key);
|
|
990
|
-
await startRedirectNavigation(fetchRequest, result, false, { preventScrollReset });
|
|
1090
|
+
await startRedirectNavigation(fetchRequest, result, false, "fetcher", { preventScrollReset });
|
|
991
1091
|
return;
|
|
992
1092
|
}
|
|
993
1093
|
if (isErrorResult(result)) {
|
|
@@ -1015,7 +1115,7 @@ function createRouter(init) {
|
|
|
1015
1115
|
* actually touch history until we've processed redirects, so we just use
|
|
1016
1116
|
* the history action from the original navigation (PUSH or REPLACE).
|
|
1017
1117
|
*/
|
|
1018
|
-
async function startRedirectNavigation(request, redirect, isNavigation, { submission, fetcherSubmission, preventScrollReset, replace } = {}) {
|
|
1118
|
+
async function startRedirectNavigation(request, redirect, isNavigation, dataStrategyInitiator, { submission, fetcherSubmission, preventScrollReset, replace } = {}) {
|
|
1019
1119
|
if (!isNavigation) {
|
|
1020
1120
|
pendingPopstateNavigationDfd?.resolve();
|
|
1021
1121
|
pendingPopstateNavigationDfd = null;
|
|
@@ -1052,20 +1152,22 @@ function createRouter(init) {
|
|
|
1052
1152
|
formAction: location
|
|
1053
1153
|
},
|
|
1054
1154
|
preventScrollReset: preventScrollReset || pendingPreventScrollReset,
|
|
1055
|
-
enableViewTransition: isNavigation ? pendingViewTransitionEnabled : void 0
|
|
1155
|
+
enableViewTransition: isNavigation ? pendingViewTransitionEnabled : void 0,
|
|
1156
|
+
dataStrategyInitiator
|
|
1056
1157
|
});
|
|
1057
1158
|
else await startNavigation(redirectNavigationType, redirectLocation, {
|
|
1058
1159
|
overrideNavigation: getLoadingNavigation(redirectLocation, [], redirectNavigationType, submission),
|
|
1059
1160
|
fetcherSubmission,
|
|
1060
1161
|
preventScrollReset: preventScrollReset || pendingPreventScrollReset,
|
|
1061
|
-
enableViewTransition: isNavigation ? pendingViewTransitionEnabled : void 0
|
|
1162
|
+
enableViewTransition: isNavigation ? pendingViewTransitionEnabled : void 0,
|
|
1163
|
+
dataStrategyInitiator
|
|
1062
1164
|
});
|
|
1063
1165
|
}
|
|
1064
|
-
async function callDataStrategy(request, path, matches, scopedContext, fetcherKey) {
|
|
1166
|
+
async function callDataStrategy(request, path, matches, scopedContext, fetcherKey, initiator, navigationType = null) {
|
|
1065
1167
|
let results;
|
|
1066
1168
|
let dataResults = {};
|
|
1067
1169
|
try {
|
|
1068
|
-
results = await callDataStrategyImpl(dataStrategyImpl, request, path, matches, fetcherKey, scopedContext, false);
|
|
1170
|
+
results = await callDataStrategyImpl(dataStrategyImpl, request, path, matches, fetcherKey, initiator, scopedContext, false, navigationType);
|
|
1069
1171
|
} catch (e) {
|
|
1070
1172
|
matches.filter((m) => m.shouldLoad).forEach((m) => {
|
|
1071
1173
|
dataResults[m.route.id] = {
|
|
@@ -1092,11 +1194,11 @@ function createRouter(init) {
|
|
|
1092
1194
|
} else dataResults[routeId] = await convertDataStrategyResultToDataResult(result);
|
|
1093
1195
|
return dataResults;
|
|
1094
1196
|
}
|
|
1095
|
-
async function callLoadersAndMaybeResolveData(matches, fetchersToLoad, request, location, scopedContext) {
|
|
1096
|
-
let loaderResultsPromise = callDataStrategy(request, location, matches, scopedContext, null);
|
|
1197
|
+
async function callLoadersAndMaybeResolveData(matches, fetchersToLoad, request, location, scopedContext, initiator, navigationType = null) {
|
|
1198
|
+
let loaderResultsPromise = callDataStrategy(request, location, matches, scopedContext, null, initiator, navigationType);
|
|
1097
1199
|
let fetcherResultsPromise = Promise.all(fetchersToLoad.map(async (f) => {
|
|
1098
1200
|
if (f.matches && f.match && f.request && f.controller) {
|
|
1099
|
-
let result = (await callDataStrategy(f.request, f.path, f.matches, scopedContext, f.key))[f.match.route.id];
|
|
1201
|
+
let result = (await callDataStrategy(f.request, f.path, f.matches, scopedContext, f.key, initiator, navigationType))[f.match.route.id];
|
|
1100
1202
|
return { [f.key]: result };
|
|
1101
1203
|
} else return Promise.resolve({ [f.key]: {
|
|
1102
1204
|
type: "error",
|
|
@@ -1110,7 +1212,8 @@ function createRouter(init) {
|
|
|
1110
1212
|
}
|
|
1111
1213
|
function interruptActiveLoads() {
|
|
1112
1214
|
isRevalidationRequired = true;
|
|
1113
|
-
fetchLoadMatches.forEach((
|
|
1215
|
+
fetchLoadMatches.forEach((loadMatch, key) => {
|
|
1216
|
+
if (future.unstable_customRouteDiscovery && loadMatch.isDiscovering) return;
|
|
1114
1217
|
if (fetchControllers.has(key)) cancelledFetcherLoads.add(key);
|
|
1115
1218
|
abortFetcher(key);
|
|
1116
1219
|
});
|
|
@@ -1136,6 +1239,8 @@ function createRouter(init) {
|
|
|
1136
1239
|
}
|
|
1137
1240
|
function resetFetcher(key, opts) {
|
|
1138
1241
|
abortFetcher(key, opts?.reason);
|
|
1242
|
+
fetchLoadMatches.delete(key);
|
|
1243
|
+
cancelledFetcherLoads.delete(key);
|
|
1139
1244
|
updateFetcherState(key, getDoneFetcher(null));
|
|
1140
1245
|
}
|
|
1141
1246
|
function deleteFetcher(fetchers, key) {
|
|
@@ -1308,6 +1413,10 @@ function createRouter(init) {
|
|
|
1308
1413
|
}
|
|
1309
1414
|
});
|
|
1310
1415
|
} catch (e) {
|
|
1416
|
+
if (future.unstable_customRouteDiscovery) {
|
|
1417
|
+
if (signal.aborted) return { type: "aborted" };
|
|
1418
|
+
if (e instanceof DiscoveryCancelledError) return { type: "cancelled" };
|
|
1419
|
+
}
|
|
1311
1420
|
return {
|
|
1312
1421
|
type: "error",
|
|
1313
1422
|
error: e,
|
|
@@ -1768,7 +1877,7 @@ function createStaticHandler(routes, opts) {
|
|
|
1768
1877
|
};
|
|
1769
1878
|
}
|
|
1770
1879
|
async function callDataStrategy(request, location, matches, isRouteRequest, requestContext, dataStrategy) {
|
|
1771
|
-
let results = await callDataStrategyImpl(dataStrategy || defaultDataStrategy, request, location, matches, null, requestContext, true);
|
|
1880
|
+
let results = await callDataStrategyImpl(dataStrategy || defaultDataStrategy, request, location, matches, null, "static", requestContext, true);
|
|
1772
1881
|
let dataResults = {};
|
|
1773
1882
|
await Promise.all(matches.map(async (match) => {
|
|
1774
1883
|
if (!(match.route.id in results)) return;
|
|
@@ -1787,6 +1896,9 @@ function createStaticHandler(routes, opts) {
|
|
|
1787
1896
|
}
|
|
1788
1897
|
return {
|
|
1789
1898
|
dataRoutes,
|
|
1899
|
+
get _matchCost() {
|
|
1900
|
+
return dataRouteMatcher instanceof V6RegExMatcher ? dataRouteMatcher.matchCost : void 0;
|
|
1901
|
+
},
|
|
1790
1902
|
match,
|
|
1791
1903
|
query,
|
|
1792
1904
|
queryRoute
|
|
@@ -2172,6 +2284,9 @@ const loadLazyRouteProperty = ({ key, route, manifest, mapRouteProperties }) =>
|
|
|
2172
2284
|
}
|
|
2173
2285
|
})();
|
|
2174
2286
|
cache[key] = propertyPromise;
|
|
2287
|
+
propertyPromise.catch(() => {
|
|
2288
|
+
if (cache[key] === propertyPromise) delete cache[key];
|
|
2289
|
+
});
|
|
2175
2290
|
return propertyPromise;
|
|
2176
2291
|
};
|
|
2177
2292
|
const lazyRouteFunctionCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -2213,7 +2328,9 @@ function loadLazyRoute(route, type, manifest, mapRouteProperties, lazyRoutePrope
|
|
|
2213
2328
|
});
|
|
2214
2329
|
})();
|
|
2215
2330
|
lazyRouteFunctionCache.set(routeToUpdate, lazyRoutePromise);
|
|
2216
|
-
lazyRoutePromise.catch(() => {
|
|
2331
|
+
lazyRoutePromise.catch(() => {
|
|
2332
|
+
if (lazyRouteFunctionCache.get(routeToUpdate) === lazyRoutePromise) lazyRouteFunctionCache.delete(routeToUpdate);
|
|
2333
|
+
});
|
|
2217
2334
|
return {
|
|
2218
2335
|
lazyRoutePromise,
|
|
2219
2336
|
lazyHandlerPromise: lazyRoutePromise
|
|
@@ -2409,7 +2526,7 @@ function getTargetedDataStrategyMatches(mapRouteProperties, manifest, request, p
|
|
|
2409
2526
|
return getDataStrategyMatch(mapRouteProperties, manifest, request, path, getRoutePattern(matches), match, lazyRoutePropertiesToSkip, scopedContext, true, shouldRevalidateArgs);
|
|
2410
2527
|
});
|
|
2411
2528
|
}
|
|
2412
|
-
async function callDataStrategyImpl(dataStrategyImpl, request, path, matches, fetcherKey, scopedContext, isStaticHandler) {
|
|
2529
|
+
async function callDataStrategyImpl(dataStrategyImpl, request, path, matches, fetcherKey, initiator, scopedContext, isStaticHandler, navigationType = null) {
|
|
2413
2530
|
if (matches.some((m) => m._lazyPromises?.middleware)) await Promise.all(matches.map((m) => m._lazyPromises?.middleware));
|
|
2414
2531
|
let dataStrategyArgs = {
|
|
2415
2532
|
request,
|
|
@@ -2417,7 +2534,9 @@ async function callDataStrategyImpl(dataStrategyImpl, request, path, matches, fe
|
|
|
2417
2534
|
pattern: getRoutePattern(matches),
|
|
2418
2535
|
params: matches[0].params,
|
|
2419
2536
|
context: scopedContext,
|
|
2420
|
-
matches
|
|
2537
|
+
matches,
|
|
2538
|
+
unstable_initiator: initiator,
|
|
2539
|
+
unstable_navigationType: initiator === "navigation" ? navigationType : null
|
|
2421
2540
|
};
|
|
2422
2541
|
let runClientMiddleware = isStaticHandler ? () => {
|
|
2423
2542
|
throw new Error("You cannot call `runClientMiddleware()` from a static handler `dataStrategy`. Middleware is run outside of `dataStrategy` during SSR in order to bubble up the Response. You can enable middleware via the `respond` API in `query`/`queryRoute`");
|
|
@@ -2503,10 +2622,13 @@ async function callLoaderOrAction({ request, path, pattern, match, lazyHandlerPr
|
|
|
2503
2622
|
pathname,
|
|
2504
2623
|
routeId: match.route.id
|
|
2505
2624
|
});
|
|
2506
|
-
} else
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2625
|
+
} else {
|
|
2626
|
+
await lazyRoutePromise;
|
|
2627
|
+
return {
|
|
2628
|
+
type: "data",
|
|
2629
|
+
result: void 0
|
|
2630
|
+
};
|
|
2631
|
+
}
|
|
2510
2632
|
}
|
|
2511
2633
|
else if (!handler) {
|
|
2512
2634
|
let url = new URL(request.url);
|
|
@@ -2701,12 +2823,12 @@ function processRouteLoaderData(matches, results, pendingActionResult, isStaticH
|
|
|
2701
2823
|
function processLoaderData(state, matches, results, pendingActionResult, revalidatingFetchers, fetcherResults, workingFetchers) {
|
|
2702
2824
|
let { loaderData, errors } = processRouteLoaderData(matches, results, pendingActionResult);
|
|
2703
2825
|
revalidatingFetchers.filter((f) => !f.matches || f.matches.some((m) => m.shouldLoad)).forEach((rf) => {
|
|
2704
|
-
let { key,
|
|
2826
|
+
let { key, routeId, controller } = rf;
|
|
2705
2827
|
if (controller && controller.signal.aborted) return;
|
|
2706
2828
|
let result = fetcherResults[key];
|
|
2707
2829
|
invariant(result, "Did not find corresponding fetcher result");
|
|
2708
2830
|
if (isErrorResult(result)) {
|
|
2709
|
-
let boundaryMatch = findNearestBoundary(state.matches,
|
|
2831
|
+
let boundaryMatch = findNearestBoundary(state.matches, routeId);
|
|
2710
2832
|
if (!(errors && errors[boundaryMatch.route.id])) errors = {
|
|
2711
2833
|
...errors,
|
|
2712
2834
|
[boundaryMatch.route.id]: result.error
|
|
@@ -3014,4 +3136,4 @@ function createDeferred() {
|
|
|
3014
3136
|
};
|
|
3015
3137
|
}
|
|
3016
3138
|
//#endregion
|
|
3017
|
-
export { IDLE_BLOCKER, IDLE_FETCHER, IDLE_NAVIGATION, createDataRouteMatcher, createRouter, createStaticHandler, getStaticContextFromError, hasInvalidProtocol, isDataWithResponseInit, isMutationMethod, isRedirectResponse, isRedirectStatusCode, isResponse };
|
|
3139
|
+
export { IDLE_BLOCKER, IDLE_FETCHER, IDLE_NAVIGATION, clientErrors, createDataRouteMatcher, createRouter, createStaticHandler, getStaticContextFromError, hasInvalidProtocol, isDataWithResponseInit, isMutationMethod, isRedirectResponse, isRedirectStatusCode, isResponse };
|