react-router 8.3.1 → 8.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +83 -0
- 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 +601 -189
- package/dist/development/index-react-server.js +100 -48
- package/dist/development/index.d.ts +10 -9
- package/dist/development/index.js +6 -5
- package/dist/development/lib/actions.js +1 -1
- package/dist/development/lib/components.js +66 -10
- package/dist/development/lib/context.d.ts +19 -6
- package/dist/development/lib/context.js +11 -3
- package/dist/development/lib/dom/dom.d.ts +3 -0
- package/dist/development/lib/dom/dom.js +1 -1
- package/dist/development/lib/dom/global.d.ts +35 -0
- package/dist/development/lib/dom/lib.d.ts +34 -9
- package/dist/development/lib/dom/lib.js +30 -37
- package/dist/development/lib/dom/server.d.ts +6 -1
- package/dist/development/lib/dom/server.js +41 -15
- package/dist/development/lib/dom/ssr/components.js +26 -31
- package/dist/development/lib/dom/ssr/data.js +1 -1
- package/dist/development/lib/dom/ssr/entry.d.ts +13 -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 +46 -22
- package/dist/development/lib/dom/ssr/hydration.d.ts +3 -1
- package/dist/development/lib/dom/ssr/hydration.js +6 -4
- 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 +5 -2
- 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 +4 -2
- package/dist/development/lib/dom/ssr/single-fetch.d.ts +28 -2
- package/dist/development/lib/dom/ssr/single-fetch.js +80 -71
- 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 +33 -12
- package/dist/development/lib/errors.js +1 -1
- package/dist/development/lib/hooks.d.ts +3 -3
- package/dist/development/lib/hooks.js +52 -47
- 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.d.ts +2 -0
- package/dist/development/lib/router/matcher-route-pattern.js +216 -0
- package/dist/development/lib/router/matcher-route-pattern.preload.d.ts +20 -0
- package/dist/development/lib/router/matcher-route-pattern.preload.js +36 -0
- package/dist/development/lib/router/matcher.d.ts +2 -0
- package/dist/development/lib/router/matcher.js +29 -0
- package/dist/development/lib/router/navigation.js +1 -1
- package/dist/development/lib/router/router.d.ts +19 -7
- package/dist/development/lib/router/router.js +235 -128
- package/dist/development/lib/router/url.js +1 -1
- package/dist/development/lib/router/utils.d.ts +30 -5
- package/dist/development/lib/router/utils.js +8 -5
- package/dist/development/lib/rsc/browser.js +3 -2
- 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 +25 -15
- package/dist/development/lib/rsc/route-modules.js +1 -1
- package/dist/development/lib/rsc/server.rsc.d.ts +10 -2
- package/dist/development/lib/rsc/server.ssr.js +25 -21
- 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 +3 -4
- 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 +18 -9
- 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 +1 -1
- 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.d.ts +3 -0
- package/dist/development/route-pattern.js +12 -0
- 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 +1 -1
- 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 +601 -189
- package/dist/production/index-react-server.js +100 -48
- package/dist/production/index.d.ts +10 -9
- package/dist/production/index.js +6 -5
- package/dist/production/lib/actions.js +1 -1
- package/dist/production/lib/components.js +66 -10
- package/dist/production/lib/context.d.ts +19 -6
- package/dist/production/lib/context.js +11 -3
- package/dist/production/lib/dom/dom.d.ts +3 -0
- package/dist/production/lib/dom/dom.js +1 -1
- package/dist/production/lib/dom/global.d.ts +35 -0
- package/dist/production/lib/dom/lib.d.ts +34 -9
- package/dist/production/lib/dom/lib.js +30 -37
- package/dist/production/lib/dom/server.d.ts +6 -1
- package/dist/production/lib/dom/server.js +41 -15
- package/dist/production/lib/dom/ssr/components.js +26 -31
- package/dist/production/lib/dom/ssr/data.js +1 -1
- package/dist/production/lib/dom/ssr/entry.d.ts +13 -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 +46 -22
- package/dist/production/lib/dom/ssr/hydration.d.ts +3 -1
- package/dist/production/lib/dom/ssr/hydration.js +6 -4
- 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 +5 -2
- 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 +4 -2
- package/dist/production/lib/dom/ssr/single-fetch.d.ts +28 -2
- package/dist/production/lib/dom/ssr/single-fetch.js +80 -71
- 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 +33 -12
- package/dist/production/lib/errors.js +1 -1
- package/dist/production/lib/hooks.d.ts +3 -3
- package/dist/production/lib/hooks.js +51 -46
- 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.d.ts +2 -0
- package/dist/production/lib/router/matcher-route-pattern.js +216 -0
- package/dist/production/lib/router/matcher-route-pattern.preload.d.ts +20 -0
- package/dist/production/lib/router/matcher-route-pattern.preload.js +36 -0
- package/dist/production/lib/router/matcher.d.ts +2 -0
- package/dist/production/lib/router/matcher.js +29 -0
- package/dist/production/lib/router/navigation.js +1 -1
- package/dist/production/lib/router/router.d.ts +19 -7
- package/dist/production/lib/router/router.js +235 -128
- package/dist/production/lib/router/url.js +1 -1
- package/dist/production/lib/router/utils.d.ts +30 -5
- package/dist/production/lib/router/utils.js +8 -5
- package/dist/production/lib/rsc/browser.js +3 -2
- 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 +25 -15
- package/dist/production/lib/rsc/route-modules.js +1 -1
- package/dist/production/lib/rsc/server.rsc.d.ts +10 -2
- package/dist/production/lib/rsc/server.ssr.js +25 -21
- 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 +3 -4
- 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 +18 -9
- 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 +1 -1
- 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.d.ts +3 -0
- package/dist/production/route-pattern.js +12 -0
- 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 +1 -1
- package/dist/production/vendor/turbo-stream-v2/utils.js +1 -1
- package/docs/explanation/lazy-route-discovery.md +4 -0
- package/docs/explanation/sessions-and-cookies.md +108 -4
- package/docs/how-to/custom-fetch.md +218 -0
- package/docs/how-to/data-strategy.md +23 -1
- package/docs/how-to/fetchers.md +6 -1
- package/docs/how-to/middleware.md +4 -1
- package/docs/how-to/optimize-revalidation.md +178 -5
- package/docs/how-to/pre-rendering.md +23 -1
- package/docs/how-to/react-server-components.md +26 -3
- package/docs/how-to/resource-routes.md +3 -0
- package/docs/how-to/route-discovery.md +145 -0
- package/docs/how-to/spa.md +2 -0
- package/docs/how-to/view-transitions.md +80 -13
- package/docs/start/data/actions.md +2 -1
- package/docs/start/data/route-object.md +21 -6
- package/docs/start/framework/actions.md +4 -2
- package/docs/start/framework/navigating.md +5 -9
- package/docs/start/framework/rendering.md +37 -0
- package/docs/start/framework/route-module.md +32 -5
- package/docs/upgrading/future.md +68 -0
- package/package.json +19 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* react-router v8.
|
|
2
|
+
* react-router v8.5.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -10,8 +10,10 @@
|
|
|
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,
|
|
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
|
+
import { V6RegExMatcher } from "./matcher.js";
|
|
16
|
+
import { getRoutePatternMatcher } from "./matcher-route-pattern.preload.js";
|
|
15
17
|
import { validateNavigationTarget } from "./navigation.js";
|
|
16
18
|
//#region lib/router/router.ts
|
|
17
19
|
const validMutationMethodsArr = [
|
|
@@ -61,18 +63,26 @@ const IDLE_BLOCKER = {
|
|
|
61
63
|
};
|
|
62
64
|
const TRANSITIONS_STORAGE_KEY = "remix-router-transitions";
|
|
63
65
|
const ResetLoaderDataSymbol = Symbol("ResetLoaderData");
|
|
66
|
+
function createDataRouteMatcher(future, basename) {
|
|
67
|
+
if (future.unstable_routePatternMatching) {
|
|
68
|
+
let RoutePatternMatcher = getRoutePatternMatcher();
|
|
69
|
+
invariant(RoutePatternMatcher, "You must call unstable_preloadRoutePattern() from \"react-router/route-pattern\" before enabling future.unstable_routePatternMatching.");
|
|
70
|
+
return new RoutePatternMatcher(basename);
|
|
71
|
+
}
|
|
72
|
+
return new V6RegExMatcher(basename);
|
|
73
|
+
}
|
|
64
74
|
/**
|
|
65
75
|
* Encapsulates the stable and in-flight route trees together with their
|
|
66
76
|
* pre-computed branch caches so the structures always stay in sync.
|
|
67
77
|
*/
|
|
68
78
|
var DataRoutes = class {
|
|
69
79
|
#routes;
|
|
70
|
-
#branches;
|
|
71
80
|
#hmrRoutes;
|
|
72
|
-
#
|
|
73
|
-
constructor(routes) {
|
|
81
|
+
#matcher;
|
|
82
|
+
constructor(routes, matcher) {
|
|
74
83
|
this.#routes = routes;
|
|
75
|
-
this.#
|
|
84
|
+
this.#matcher = matcher;
|
|
85
|
+
this.#matcher.update(routes);
|
|
76
86
|
}
|
|
77
87
|
/** The stable route tree */
|
|
78
88
|
get stableRoutes() {
|
|
@@ -82,33 +92,29 @@ var DataRoutes = class {
|
|
|
82
92
|
get activeRoutes() {
|
|
83
93
|
return this.#hmrRoutes ?? this.#routes;
|
|
84
94
|
}
|
|
85
|
-
/** Pre-computed branches */
|
|
86
|
-
get branches() {
|
|
87
|
-
return this.#hmrBranches ?? this.#branches;
|
|
88
|
-
}
|
|
89
95
|
get hasHMRRoutes() {
|
|
90
96
|
return this.#hmrRoutes != null;
|
|
91
97
|
}
|
|
92
98
|
/** Replace the stable route tree and recompute its branches */
|
|
93
99
|
setRoutes(routes) {
|
|
94
100
|
this.#routes = routes;
|
|
95
|
-
this.#
|
|
101
|
+
if (!this.#hmrRoutes) this.#matcher.update(routes);
|
|
96
102
|
}
|
|
97
103
|
/** Set a new in-flight route tree and recompute its branches */
|
|
98
104
|
setHmrRoutes(routes) {
|
|
99
105
|
this.#hmrRoutes = routes;
|
|
100
|
-
this.#
|
|
106
|
+
this.#matcher.update(routes);
|
|
101
107
|
}
|
|
102
108
|
/** Commit in-flight routes/branches to the stable slot and clear in-flight */
|
|
103
109
|
commitHmrRoutes() {
|
|
104
110
|
if (this.#hmrRoutes) {
|
|
105
111
|
this.#routes = this.#hmrRoutes;
|
|
106
|
-
this.#branches = this.#hmrBranches;
|
|
107
112
|
this.#hmrRoutes = void 0;
|
|
108
|
-
this.#
|
|
113
|
+
this.#matcher.update(this.#routes);
|
|
109
114
|
}
|
|
110
115
|
}
|
|
111
116
|
};
|
|
117
|
+
const clientErrors = /* @__PURE__ */ new WeakMap();
|
|
112
118
|
/**
|
|
113
119
|
* Create a router and listen to history POP navigations
|
|
114
120
|
*/
|
|
@@ -128,20 +134,20 @@ function createRouter(init) {
|
|
|
128
134
|
};
|
|
129
135
|
};
|
|
130
136
|
}
|
|
131
|
-
let
|
|
132
|
-
let dataRoutes = new DataRoutes(convertRoutesToDataRoutes(init.routes, mapRouteProperties, void 0, manifest));
|
|
137
|
+
let future = { ...init.future };
|
|
133
138
|
let basename = init.basename || "/";
|
|
134
139
|
if (!basename.startsWith("/")) basename = `/${basename}`;
|
|
140
|
+
let dataRouteMatcher = createDataRouteMatcher(future, basename);
|
|
141
|
+
let manifest = {};
|
|
142
|
+
let dataRoutes = new DataRoutes(convertRoutesToDataRoutes(init.routes, mapRouteProperties, void 0, manifest), dataRouteMatcher);
|
|
135
143
|
let dataStrategyImpl = init.dataStrategy || defaultDataStrategyWithMiddleware;
|
|
136
|
-
let future = { ...init.future };
|
|
137
144
|
let unlistenHistory = null;
|
|
138
145
|
let subscribers = /* @__PURE__ */ new Set();
|
|
139
|
-
let bufferedInitialStateUpdate = null;
|
|
140
146
|
let savedScrollPositions = null;
|
|
141
147
|
let getScrollRestorationKey = null;
|
|
142
148
|
let getScrollPosition = null;
|
|
143
149
|
let initialScrollRestored = init.hydrationData != null;
|
|
144
|
-
let initialMatches =
|
|
150
|
+
let initialMatches = dataRouteMatcher.match(init.history.location);
|
|
145
151
|
let initialMatchesIsFOW = false;
|
|
146
152
|
let initialErrors = null;
|
|
147
153
|
let initialized;
|
|
@@ -155,13 +161,13 @@ function createRouter(init) {
|
|
|
155
161
|
initialErrors = { [route.id]: error };
|
|
156
162
|
} else {
|
|
157
163
|
if (initialMatches && !init.hydrationData) {
|
|
158
|
-
if (checkFogOfWar(initialMatches,
|
|
164
|
+
if (checkFogOfWar(initialMatches, init.history.location.pathname).active) initialMatches = null;
|
|
159
165
|
}
|
|
160
166
|
if (!initialMatches) {
|
|
161
167
|
initialized = false;
|
|
162
168
|
renderFallback = !initialized;
|
|
163
169
|
initialMatches = [];
|
|
164
|
-
let fogOfWar = checkFogOfWar(null,
|
|
170
|
+
let fogOfWar = checkFogOfWar(null, init.history.location.pathname);
|
|
165
171
|
if (fogOfWar.active && fogOfWar.matches) {
|
|
166
172
|
initialMatchesIsFOW = true;
|
|
167
173
|
initialMatches = fogOfWar.matches;
|
|
@@ -207,6 +213,8 @@ function createRouter(init) {
|
|
|
207
213
|
blockers: /* @__PURE__ */ new Map()
|
|
208
214
|
};
|
|
209
215
|
let pendingAction = "POP";
|
|
216
|
+
let pendingPopstateDelta = 0;
|
|
217
|
+
let pendingDiscoveryCancellation;
|
|
210
218
|
let pendingPopstateNavigationDfd = null;
|
|
211
219
|
let pendingPreventScrollReset = false;
|
|
212
220
|
let pendingNavigationController;
|
|
@@ -267,6 +275,7 @@ function createRouter(init) {
|
|
|
267
275
|
pendingPopstateNavigationDfd = null;
|
|
268
276
|
return;
|
|
269
277
|
}
|
|
278
|
+
if (future.unstable_customRouteDiscovery) pendingPopstateDelta += delta || 0;
|
|
270
279
|
return startNavigation(historyAction, location);
|
|
271
280
|
});
|
|
272
281
|
if (isBrowser) {
|
|
@@ -288,19 +297,16 @@ function createRouter(init) {
|
|
|
288
297
|
}
|
|
289
298
|
function subscribe(fn) {
|
|
290
299
|
subscribers.add(fn);
|
|
291
|
-
if (bufferedInitialStateUpdate) {
|
|
292
|
-
let { newErrors } = bufferedInitialStateUpdate;
|
|
293
|
-
bufferedInitialStateUpdate = null;
|
|
294
|
-
fn(state, {
|
|
295
|
-
deletedFetchers: [],
|
|
296
|
-
newErrors,
|
|
297
|
-
viewTransitionOpts: void 0,
|
|
298
|
-
flushSync: false
|
|
299
|
-
});
|
|
300
|
-
}
|
|
301
300
|
return () => subscribers.delete(fn);
|
|
302
301
|
}
|
|
303
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
|
+
}
|
|
304
310
|
if (newState.matches) newState.matches = newState.matches.map((m) => {
|
|
305
311
|
let route = manifest[m.route.id];
|
|
306
312
|
let matchRoute = m.route;
|
|
@@ -323,10 +329,9 @@ function createRouter(init) {
|
|
|
323
329
|
fetchersQueuedForDeletion.forEach((key) => {
|
|
324
330
|
if (!state.fetchers.has(key) && !fetchControllers.has(key)) unmountedFetchers.push(key);
|
|
325
331
|
});
|
|
326
|
-
if (subscribers.size === 0) bufferedInitialStateUpdate = { newErrors: newState.errors ?? null };
|
|
327
332
|
[...subscribers].forEach((subscriber) => subscriber(state, {
|
|
328
333
|
deletedFetchers: unmountedFetchers,
|
|
329
|
-
newErrors
|
|
334
|
+
newErrors,
|
|
330
335
|
viewTransitionOpts: opts.viewTransitionOpts,
|
|
331
336
|
flushSync: opts.flushSync === true
|
|
332
337
|
}));
|
|
@@ -352,7 +357,7 @@ function createRouter(init) {
|
|
|
352
357
|
if (isUninterruptedRevalidation) {} else if (pendingAction === "POP") {} else if (pendingAction === "PUSH") init.history.push(location, location.state);
|
|
353
358
|
else if (pendingAction === "REPLACE") init.history.replace(location, location.state);
|
|
354
359
|
let viewTransitionOpts;
|
|
355
|
-
if (pendingAction === "POP") {
|
|
360
|
+
if (pendingAction === "POP" && !isUninterruptedRevalidation && location !== state.location) {
|
|
356
361
|
let priorPaths = appliedViewTransitions.get(state.location.pathname);
|
|
357
362
|
if (priorPaths && priorPaths.has(location.pathname)) viewTransitionOpts = {
|
|
358
363
|
currentLocation: state.location,
|
|
@@ -391,17 +396,22 @@ function createRouter(init) {
|
|
|
391
396
|
viewTransitionOpts,
|
|
392
397
|
flushSync: flushSync === true
|
|
393
398
|
});
|
|
399
|
+
resetPendingNavigation();
|
|
400
|
+
pendingPopstateNavigationDfd?.resolve();
|
|
401
|
+
pendingPopstateNavigationDfd = null;
|
|
402
|
+
pendingRevalidationDfd?.resolve();
|
|
403
|
+
pendingRevalidationDfd = null;
|
|
404
|
+
}
|
|
405
|
+
function resetPendingNavigation() {
|
|
406
|
+
pendingPopstateDelta = 0;
|
|
394
407
|
pendingAction = "POP";
|
|
395
408
|
pendingPreventScrollReset = false;
|
|
396
409
|
pendingViewTransitionEnabled = false;
|
|
397
410
|
isUninterruptedRevalidation = false;
|
|
398
411
|
isRevalidationRequired = false;
|
|
399
|
-
pendingPopstateNavigationDfd?.resolve();
|
|
400
|
-
pendingPopstateNavigationDfd = null;
|
|
401
|
-
pendingRevalidationDfd?.resolve();
|
|
402
|
-
pendingRevalidationDfd = null;
|
|
403
412
|
}
|
|
404
413
|
async function navigate(to, opts) {
|
|
414
|
+
if (pendingDiscoveryCancellation) await pendingDiscoveryCancellation;
|
|
405
415
|
pendingPopstateNavigationDfd?.resolve();
|
|
406
416
|
pendingPopstateNavigationDfd = null;
|
|
407
417
|
if (typeof to === "number") {
|
|
@@ -478,22 +488,28 @@ function createRouter(init) {
|
|
|
478
488
|
});
|
|
479
489
|
}
|
|
480
490
|
function revalidate() {
|
|
491
|
+
if (pendingDiscoveryCancellation) return pendingDiscoveryCancellation.then(revalidate);
|
|
481
492
|
if (!pendingRevalidationDfd) pendingRevalidationDfd = createDeferred();
|
|
482
493
|
interruptActiveLoads();
|
|
483
494
|
updateState({ revalidation: "loading" });
|
|
484
495
|
let promise = pendingRevalidationDfd.promise;
|
|
485
496
|
if (state.navigation.state === "submitting") return promise;
|
|
486
497
|
if (state.navigation.state === "idle") {
|
|
487
|
-
startNavigation(state.historyAction, state.location, {
|
|
498
|
+
startNavigation(state.historyAction, state.location, {
|
|
499
|
+
startUninterruptedRevalidation: true,
|
|
500
|
+
dataStrategyInitiator: "revalidation"
|
|
501
|
+
});
|
|
488
502
|
return promise;
|
|
489
503
|
}
|
|
490
504
|
startNavigation(pendingAction || state.historyAction, state.navigation.location, {
|
|
491
505
|
overrideNavigation: state.navigation,
|
|
506
|
+
dataStrategyInitiator: "revalidation",
|
|
492
507
|
enableViewTransition: pendingViewTransitionEnabled === true
|
|
493
508
|
});
|
|
494
509
|
return promise;
|
|
495
510
|
}
|
|
496
511
|
async function startNavigation(historyAction, location, opts) {
|
|
512
|
+
if (pendingDiscoveryCancellation) await pendingDiscoveryCancellation;
|
|
497
513
|
pendingNavigationController && pendingNavigationController.abort();
|
|
498
514
|
pendingNavigationController = null;
|
|
499
515
|
pendingAction = historyAction;
|
|
@@ -501,14 +517,13 @@ function createRouter(init) {
|
|
|
501
517
|
saveScrollPosition(state.location, state.matches);
|
|
502
518
|
pendingPreventScrollReset = (opts && opts.preventScrollReset) === true;
|
|
503
519
|
pendingViewTransitionEnabled = (opts && opts.enableViewTransition) === true;
|
|
504
|
-
let
|
|
505
|
-
let matches = opts?.initialHydration && state.matches && state.matches.length > 0 && !initialMatchesIsFOW ? state.matches : matchRoutesImpl(routesToUse, location, basename, false, dataRoutes.branches);
|
|
520
|
+
let matches = opts?.initialHydration && state.matches && state.matches.length > 0 && !initialMatchesIsFOW ? state.matches : dataRouteMatcher.match(location);
|
|
506
521
|
let flushSync = (opts && opts.flushSync) === true;
|
|
507
522
|
if (matches && state.initialized && !isRevalidationRequired && isHashChangeOnly(state.location, location) && !(opts && opts.submission && isMutationMethod(opts.submission.formMethod))) {
|
|
508
523
|
completeNavigation(location, { matches }, { flushSync });
|
|
509
524
|
return;
|
|
510
525
|
}
|
|
511
|
-
let fogOfWar = checkFogOfWar(matches,
|
|
526
|
+
let fogOfWar = checkFogOfWar(matches, location.pathname);
|
|
512
527
|
if (fogOfWar.active && fogOfWar.matches) matches = fogOfWar.matches;
|
|
513
528
|
if (opts?.instrumentationNavigateMetaReceiver) {
|
|
514
529
|
let meta = getInstrumentationNavigateMeta(init.history, location, matches);
|
|
@@ -530,6 +545,7 @@ function createRouter(init) {
|
|
|
530
545
|
} : void 0;
|
|
531
546
|
pendingNavigationController = new AbortController();
|
|
532
547
|
let request = createClientSideRequest(init.history, location, pendingNavigationController.signal, opts && opts.submission);
|
|
548
|
+
let dataStrategyInitiator = opts?.initialHydration ? "initialization" : opts?.dataStrategyInitiator ?? "navigation";
|
|
533
549
|
let scopedContext = init.getContext ? await init.getContext() : new RouterContextProvider();
|
|
534
550
|
let pendingActionResult;
|
|
535
551
|
if (opts && opts.pendingError) pendingActionResult = [findNearestBoundary(matches).route.id, {
|
|
@@ -537,7 +553,7 @@ function createRouter(init) {
|
|
|
537
553
|
error: opts.pendingError
|
|
538
554
|
}];
|
|
539
555
|
else if (opts && opts.submission && isMutationMethod(opts.submission.formMethod)) {
|
|
540
|
-
let actionResult = await handleAction(request, location, opts.submission, matches, historyAction, scopedContext, fogOfWar.active, opts && opts.initialHydration === true, {
|
|
556
|
+
let actionResult = await handleAction(request, dataStrategyInitiator, location, opts.submission, matches, historyAction, scopedContext, fogOfWar.active, opts && opts.initialHydration === true, {
|
|
541
557
|
replace: opts.replace,
|
|
542
558
|
flushSync
|
|
543
559
|
});
|
|
@@ -561,7 +577,7 @@ function createRouter(init) {
|
|
|
561
577
|
fogOfWar.active = false;
|
|
562
578
|
request = createClientSideRequest(init.history, request.url, request.signal);
|
|
563
579
|
}
|
|
564
|
-
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);
|
|
580
|
+
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);
|
|
565
581
|
if (shortCircuited) return;
|
|
566
582
|
pendingNavigationController = null;
|
|
567
583
|
completeNavigation(location, {
|
|
@@ -572,13 +588,57 @@ function createRouter(init) {
|
|
|
572
588
|
...workingFetchers ? { fetchers: workingFetchers } : {}
|
|
573
589
|
});
|
|
574
590
|
}
|
|
575
|
-
|
|
576
|
-
|
|
591
|
+
function cancelDiscoveryNavigation() {
|
|
592
|
+
let cancellation = createDeferred();
|
|
593
|
+
pendingDiscoveryCancellation = cancellation.promise;
|
|
594
|
+
let delta = pendingPopstateDelta;
|
|
595
|
+
let popstateNavigationDfd = pendingPopstateNavigationDfd;
|
|
596
|
+
pendingPopstateNavigationDfd = null;
|
|
597
|
+
pendingNavigationController?.abort();
|
|
598
|
+
pendingNavigationController = null;
|
|
599
|
+
resetPendingNavigation();
|
|
600
|
+
pendingRevalidationDfd?.resolve();
|
|
601
|
+
pendingRevalidationDfd = null;
|
|
602
|
+
let blockers = new Map(state.blockers);
|
|
603
|
+
blockers.forEach((blocker, key) => {
|
|
604
|
+
if (blocker.state === "proceeding") blockers.set(key, IDLE_BLOCKER);
|
|
605
|
+
});
|
|
606
|
+
let fetchers = new Map(state.fetchers);
|
|
607
|
+
let didUpdateFetchers = markFetchRedirectsDone(fetchers);
|
|
608
|
+
fetchers.forEach((fetcher, key) => {
|
|
609
|
+
if (fetcher.state === "loading" && !fetchControllers.has(key)) {
|
|
610
|
+
fetchers.set(key, getDoneFetcher(fetcher.data));
|
|
611
|
+
didUpdateFetchers = true;
|
|
612
|
+
}
|
|
613
|
+
});
|
|
614
|
+
cancelledFetcherLoads.clear();
|
|
615
|
+
updateState({
|
|
616
|
+
navigation: IDLE_NAVIGATION,
|
|
617
|
+
revalidation: "idle",
|
|
618
|
+
blockers,
|
|
619
|
+
...didUpdateFetchers ? { fetchers } : {}
|
|
620
|
+
});
|
|
621
|
+
function finishCancellation() {
|
|
622
|
+
pendingDiscoveryCancellation = void 0;
|
|
623
|
+
popstateNavigationDfd?.resolve();
|
|
624
|
+
cancellation.resolve();
|
|
625
|
+
}
|
|
626
|
+
if (delta) {
|
|
627
|
+
unblockBlockerHistoryUpdate = finishCancellation;
|
|
628
|
+
init.history.go(-delta);
|
|
629
|
+
} else finishCancellation();
|
|
630
|
+
return cancellation.promise;
|
|
631
|
+
}
|
|
632
|
+
async function handleAction(request, dataStrategyInitiator, location, submission, matches, historyAction, scopedContext, isFogOfWar, initialHydration, opts = {}) {
|
|
633
|
+
if (!future.unstable_customRouteDiscovery) interruptActiveLoads();
|
|
577
634
|
updateState({ navigation: getSubmittingNavigation(location, matches, historyAction, submission) }, { flushSync: opts.flushSync === true });
|
|
578
635
|
if (isFogOfWar) {
|
|
579
636
|
let discoverResult = await discoverRoutes(matches, location.pathname, request.signal);
|
|
580
|
-
if (discoverResult.type === "aborted") return { shortCircuited: true };
|
|
581
|
-
else if (discoverResult.type === "
|
|
637
|
+
if (future.unstable_customRouteDiscovery && request.signal.aborted || discoverResult.type === "aborted") return { shortCircuited: true };
|
|
638
|
+
else if (discoverResult.type === "cancelled") {
|
|
639
|
+
await cancelDiscoveryNavigation();
|
|
640
|
+
return { shortCircuited: true };
|
|
641
|
+
} else if (discoverResult.type === "error") {
|
|
582
642
|
if (discoverResult.partialMatches.length === 0) {
|
|
583
643
|
let { matches, route } = getShortCircuitMatches(dataRoutes.activeRoutes);
|
|
584
644
|
return {
|
|
@@ -608,6 +668,7 @@ function createRouter(init) {
|
|
|
608
668
|
};
|
|
609
669
|
} else matches = discoverResult.matches;
|
|
610
670
|
}
|
|
671
|
+
if (future.unstable_customRouteDiscovery) interruptActiveLoads();
|
|
611
672
|
let result;
|
|
612
673
|
let actionMatch = getTargetMatch(matches, location);
|
|
613
674
|
if (!actionMatch.route.action && !actionMatch.route.lazy) result = {
|
|
@@ -619,7 +680,7 @@ function createRouter(init) {
|
|
|
619
680
|
})
|
|
620
681
|
};
|
|
621
682
|
else {
|
|
622
|
-
let results = await callDataStrategy(request, location, getTargetedDataStrategyMatches(mapRouteProperties, manifest, request, location, matches, actionMatch, initialHydration ? [] : hydrationRouteProperties, scopedContext), scopedContext, null);
|
|
683
|
+
let results = await callDataStrategy(request, location, getTargetedDataStrategyMatches(mapRouteProperties, manifest, request, location, matches, actionMatch, initialHydration ? [] : hydrationRouteProperties, scopedContext), scopedContext, null, dataStrategyInitiator, historyAction);
|
|
623
684
|
result = results[actionMatch.route.id];
|
|
624
685
|
if (!result) {
|
|
625
686
|
for (let match of matches) if (results[match.route.id]) {
|
|
@@ -633,7 +694,7 @@ function createRouter(init) {
|
|
|
633
694
|
let replace;
|
|
634
695
|
if (opts && opts.replace != null) replace = opts.replace;
|
|
635
696
|
else replace = normalizeRedirectLocation(result.response.headers.get("Location"), new URL(request.url), basename, init.history) === state.location.pathname + state.location.search;
|
|
636
|
-
await startRedirectNavigation(request, result, true, {
|
|
697
|
+
await startRedirectNavigation(request, result, true, dataStrategyInitiator, {
|
|
637
698
|
submission,
|
|
638
699
|
replace
|
|
639
700
|
});
|
|
@@ -656,7 +717,7 @@ function createRouter(init) {
|
|
|
656
717
|
pendingActionResult: [actionMatch.route.id, result]
|
|
657
718
|
};
|
|
658
719
|
}
|
|
659
|
-
async function handleLoaders(request, location, matches, historyAction, scopedContext, isFogOfWar, overrideNavigation, submission, fetcherSubmission, replace, initialHydration, flushSync, pendingActionResult, callSiteDefaultShouldRevalidate) {
|
|
720
|
+
async function handleLoaders(request, dataStrategyInitiator, location, matches, historyAction, scopedContext, isFogOfWar, overrideNavigation, submission, fetcherSubmission, replace, initialHydration, flushSync, pendingActionResult, callSiteDefaultShouldRevalidate) {
|
|
660
721
|
let loadingNavigation = overrideNavigation || getLoadingNavigation(location, matches, historyAction, submission);
|
|
661
722
|
let activeSubmission = submission || fetcherSubmission || getSubmissionFromNavigation(loadingNavigation);
|
|
662
723
|
let shouldUpdateNavigationState = !isUninterruptedRevalidation && !initialHydration;
|
|
@@ -669,8 +730,11 @@ function createRouter(init) {
|
|
|
669
730
|
}, { flushSync });
|
|
670
731
|
}
|
|
671
732
|
let discoverResult = await discoverRoutes(matches, location.pathname, request.signal);
|
|
672
|
-
if (discoverResult.type === "aborted") return { shortCircuited: true };
|
|
673
|
-
else if (discoverResult.type === "
|
|
733
|
+
if (future.unstable_customRouteDiscovery && request.signal.aborted || discoverResult.type === "aborted") return { shortCircuited: true };
|
|
734
|
+
else if (discoverResult.type === "cancelled") {
|
|
735
|
+
await cancelDiscoveryNavigation();
|
|
736
|
+
return { shortCircuited: true };
|
|
737
|
+
} else if (discoverResult.type === "error") {
|
|
674
738
|
if (discoverResult.partialMatches.length === 0) {
|
|
675
739
|
let { matches, route } = getShortCircuitMatches(dataRoutes.activeRoutes);
|
|
676
740
|
return {
|
|
@@ -692,10 +756,12 @@ function createRouter(init) {
|
|
|
692
756
|
loaderData: {},
|
|
693
757
|
errors: { [route.id]: error }
|
|
694
758
|
};
|
|
695
|
-
} else
|
|
759
|
+
} else {
|
|
760
|
+
matches = discoverResult.matches;
|
|
761
|
+
if (initialHydration && !request.signal.aborted) updateState({ matches });
|
|
762
|
+
}
|
|
696
763
|
}
|
|
697
|
-
let
|
|
698
|
-
let { dsMatches, revalidatingFetchers } = getMatchesToLoad(request, scopedContext, mapRouteProperties, manifest, init.history, state, matches, activeSubmission, location, initialHydration ? [] : hydrationRouteProperties, initialHydration === true, isRevalidationRequired, cancelledFetcherLoads, fetchersQueuedForDeletion, fetchLoadMatches, fetchRedirectIds, routesToUse, basename, init.patchRoutesOnNavigation != null, dataRoutes.branches, pendingActionResult, callSiteDefaultShouldRevalidate);
|
|
764
|
+
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);
|
|
699
765
|
pendingNavigationLoadId = ++incrementingLoadId;
|
|
700
766
|
if (!init.dataStrategy && !dsMatches.some((m) => m.shouldLoad) && !dsMatches.some((m) => m.route.middleware && m.route.middleware.length > 0) && revalidatingFetchers.length === 0) {
|
|
701
767
|
let workingFetchers = new Map(state.fetchers);
|
|
@@ -725,27 +791,31 @@ function createRouter(init) {
|
|
|
725
791
|
});
|
|
726
792
|
let abortPendingFetchRevalidations = () => revalidatingFetchers.forEach((f) => abortFetcher(f.key));
|
|
727
793
|
if (pendingNavigationController) pendingNavigationController.signal.addEventListener("abort", abortPendingFetchRevalidations);
|
|
728
|
-
let { loaderResults, fetcherResults } = await callLoadersAndMaybeResolveData(dsMatches, revalidatingFetchers, request, location, scopedContext);
|
|
794
|
+
let { loaderResults, fetcherResults } = await callLoadersAndMaybeResolveData(dsMatches, revalidatingFetchers, request, location, scopedContext, dataStrategyInitiator, historyAction);
|
|
729
795
|
if (request.signal.aborted) return { shortCircuited: true };
|
|
730
796
|
if (pendingNavigationController) pendingNavigationController.signal.removeEventListener("abort", abortPendingFetchRevalidations);
|
|
731
797
|
revalidatingFetchers.forEach((rf) => fetchControllers.delete(rf.key));
|
|
732
798
|
let redirect = findRedirect(loaderResults);
|
|
733
799
|
if (redirect) {
|
|
734
|
-
await startRedirectNavigation(request, redirect.result, true, { replace });
|
|
800
|
+
await startRedirectNavigation(request, redirect.result, true, dataStrategyInitiator, { replace });
|
|
735
801
|
return { shortCircuited: true };
|
|
736
802
|
}
|
|
737
803
|
redirect = findRedirect(fetcherResults);
|
|
738
804
|
if (redirect) {
|
|
739
805
|
fetchRedirectIds.add(redirect.key);
|
|
740
|
-
await startRedirectNavigation(request, redirect.result, true, { replace });
|
|
806
|
+
await startRedirectNavigation(request, redirect.result, true, dataStrategyInitiator, { replace });
|
|
741
807
|
return { shortCircuited: true };
|
|
742
808
|
}
|
|
743
809
|
let workingFetchers = new Map(state.fetchers);
|
|
744
810
|
let { loaderData, errors } = processLoaderData(state, matches, loaderResults, pendingActionResult, revalidatingFetchers, fetcherResults, workingFetchers);
|
|
745
|
-
if (initialHydration && state.errors)
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
811
|
+
if (initialHydration && state.errors) {
|
|
812
|
+
let newClientErrors = errors ?? null;
|
|
813
|
+
errors = {
|
|
814
|
+
...state.errors,
|
|
815
|
+
...errors
|
|
816
|
+
};
|
|
817
|
+
clientErrors.set(errors, newClientErrors);
|
|
818
|
+
}
|
|
749
819
|
let didUpdateFetcherRedirects = markFetchRedirectsDone(workingFetchers);
|
|
750
820
|
let didAbortFetchLoads = abortStaleFetchLoads(pendingNavigationLoadId, workingFetchers);
|
|
751
821
|
let shouldUpdateFetchers = didUpdateFetcherRedirects || didAbortFetchLoads || revalidatingFetchers.length > 0;
|
|
@@ -771,13 +841,13 @@ function createRouter(init) {
|
|
|
771
841
|
return workingFetchers;
|
|
772
842
|
}
|
|
773
843
|
async function fetch(key, routeId, href, opts) {
|
|
844
|
+
if (pendingDiscoveryCancellation) await pendingDiscoveryCancellation;
|
|
774
845
|
abortFetcher(key);
|
|
775
846
|
let flushSync = (opts && opts.flushSync) === true;
|
|
776
847
|
let instrumentationResultMetaReceiver = consumeInstrumentationClientResultMetaReceiver(router);
|
|
777
|
-
let routesToUse = dataRoutes.activeRoutes;
|
|
778
848
|
let normalizedPath = normalizeTo(state.location, state.matches, basename, href, routeId, opts?.relative);
|
|
779
|
-
let matches =
|
|
780
|
-
let fogOfWar = checkFogOfWar(matches,
|
|
849
|
+
let matches = dataRouteMatcher.match(normalizedPath);
|
|
850
|
+
let fogOfWar = checkFogOfWar(matches, normalizedPath);
|
|
781
851
|
if (fogOfWar.active && fogOfWar.matches) matches = fogOfWar.matches;
|
|
782
852
|
if (instrumentationResultMetaReceiver) instrumentationResultMetaReceiver(getInstrumentationNavigateMeta(init.history, normalizedPath, matches));
|
|
783
853
|
if (!matches) {
|
|
@@ -795,22 +865,31 @@ function createRouter(init) {
|
|
|
795
865
|
await handleFetcherAction(key, routeId, path, matches, scopedContext, fogOfWar.active, flushSync, preventScrollReset, submission, opts && opts.defaultShouldRevalidate);
|
|
796
866
|
return;
|
|
797
867
|
}
|
|
798
|
-
|
|
868
|
+
let loadMatch = {
|
|
799
869
|
routeId,
|
|
800
|
-
path
|
|
801
|
-
|
|
802
|
-
|
|
870
|
+
path,
|
|
871
|
+
isDiscovering: fogOfWar.active
|
|
872
|
+
};
|
|
873
|
+
fetchLoadMatches.set(key, loadMatch);
|
|
874
|
+
await handleFetcherLoader(key, loadMatch, matches, scopedContext, flushSync, preventScrollReset, submission);
|
|
803
875
|
}
|
|
804
876
|
async function handleFetcherAction(key, routeId, path, requestMatches, scopedContext, isFogOfWar, flushSync, preventScrollReset, submission, callSiteDefaultShouldRevalidate) {
|
|
805
|
-
interruptActiveLoads();
|
|
877
|
+
if (!future.unstable_customRouteDiscovery) interruptActiveLoads();
|
|
806
878
|
fetchLoadMatches.delete(key);
|
|
807
|
-
|
|
879
|
+
let existingFetcher = state.fetchers.get(key);
|
|
880
|
+
updateFetcherState(key, getSubmittingFetcher(submission, existingFetcher), { flushSync });
|
|
808
881
|
let abortController = new AbortController();
|
|
882
|
+
if (future.unstable_customRouteDiscovery) fetchControllers.set(key, abortController);
|
|
809
883
|
let fetchRequest = createClientSideRequest(init.history, path, abortController.signal, submission);
|
|
810
884
|
if (isFogOfWar) {
|
|
811
885
|
let discoverResult = await discoverRoutes(requestMatches, new URL(fetchRequest.url).pathname, fetchRequest.signal, key);
|
|
812
|
-
if (discoverResult.type === "aborted") return;
|
|
813
|
-
else if (discoverResult.type === "
|
|
886
|
+
if (future.unstable_customRouteDiscovery && fetchRequest.signal.aborted || discoverResult.type === "aborted") return;
|
|
887
|
+
else if (discoverResult.type === "cancelled") {
|
|
888
|
+
fetchControllers.delete(key);
|
|
889
|
+
fetchLoadMatches.delete(key);
|
|
890
|
+
updateFetcherState(key, getDoneFetcher(existingFetcher?.data), { flushSync });
|
|
891
|
+
return;
|
|
892
|
+
} else if (discoverResult.type === "error") {
|
|
814
893
|
setFetcherError(key, routeId, discoverResult.error, { flushSync });
|
|
815
894
|
return;
|
|
816
895
|
} else if (!discoverResult.matches) {
|
|
@@ -827,10 +906,11 @@ function createRouter(init) {
|
|
|
827
906
|
}), { flushSync });
|
|
828
907
|
return;
|
|
829
908
|
}
|
|
909
|
+
if (future.unstable_customRouteDiscovery) interruptActiveLoads();
|
|
830
910
|
fetchControllers.set(key, abortController);
|
|
831
911
|
let originatingLoadId = incrementingLoadId;
|
|
832
912
|
let fetchMatches = getTargetedDataStrategyMatches(mapRouteProperties, manifest, fetchRequest, path, requestMatches, match, hydrationRouteProperties, scopedContext);
|
|
833
|
-
let actionResults = await callDataStrategy(fetchRequest, path, fetchMatches, scopedContext, key);
|
|
913
|
+
let actionResults = await callDataStrategy(fetchRequest, path, fetchMatches, scopedContext, key, "fetcher");
|
|
834
914
|
let actionResult = actionResults[match.route.id];
|
|
835
915
|
if (!actionResult) {
|
|
836
916
|
for (let match of fetchMatches) if (actionResults[match.route.id]) {
|
|
@@ -856,7 +936,7 @@ function createRouter(init) {
|
|
|
856
936
|
} else {
|
|
857
937
|
fetchRedirectIds.add(key);
|
|
858
938
|
updateFetcherState(key, getLoadingFetcher(submission));
|
|
859
|
-
return startRedirectNavigation(fetchRequest, actionResult, false, {
|
|
939
|
+
return startRedirectNavigation(fetchRequest, actionResult, false, "fetcher", {
|
|
860
940
|
fetcherSubmission: submission,
|
|
861
941
|
preventScrollReset
|
|
862
942
|
});
|
|
@@ -869,12 +949,11 @@ function createRouter(init) {
|
|
|
869
949
|
}
|
|
870
950
|
let nextLocation = state.navigation.location || state.location;
|
|
871
951
|
let revalidationRequest = createClientSideRequest(init.history, nextLocation, abortController.signal);
|
|
872
|
-
let
|
|
873
|
-
let matches = state.navigation.state !== "idle" ? matchRoutesImpl(routesToUse, state.navigation.location, basename, false, dataRoutes.branches) : state.matches;
|
|
952
|
+
let matches = state.navigation.state !== "idle" ? dataRouteMatcher.match(state.navigation.location) : state.matches;
|
|
874
953
|
invariant(matches, "Didn't find any matches after fetcher action");
|
|
875
954
|
let loadId = ++incrementingLoadId;
|
|
876
955
|
fetchReloadIds.set(key, loadId);
|
|
877
|
-
let { dsMatches, revalidatingFetchers } = getMatchesToLoad(revalidationRequest, scopedContext, mapRouteProperties, manifest, init.history, state, matches, submission, nextLocation, hydrationRouteProperties, false, isRevalidationRequired, cancelledFetcherLoads, fetchersQueuedForDeletion, fetchLoadMatches, fetchRedirectIds,
|
|
956
|
+
let { dsMatches, revalidatingFetchers } = getMatchesToLoad(revalidationRequest, scopedContext, mapRouteProperties, manifest, init.history, state, matches, submission, nextLocation, hydrationRouteProperties, false, isRevalidationRequired, cancelledFetcherLoads, fetchersQueuedForDeletion, fetchLoadMatches, fetchRedirectIds, dataRouteMatcher, [match.route.id, actionResult], callSiteDefaultShouldRevalidate);
|
|
878
957
|
let loadFetcher = getLoadingFetcher(submission, actionResult.data);
|
|
879
958
|
let workingFetchers = new Map(state.fetchers);
|
|
880
959
|
workingFetchers.set(key, loadFetcher);
|
|
@@ -889,7 +968,7 @@ function createRouter(init) {
|
|
|
889
968
|
updateState({ fetchers: workingFetchers });
|
|
890
969
|
let abortPendingFetchRevalidations = () => revalidatingFetchers.forEach((rf) => abortFetcher(rf.key));
|
|
891
970
|
abortController.signal.addEventListener("abort", abortPendingFetchRevalidations);
|
|
892
|
-
let { loaderResults, fetcherResults } = await callLoadersAndMaybeResolveData(dsMatches, revalidatingFetchers, revalidationRequest, nextLocation, scopedContext);
|
|
971
|
+
let { loaderResults, fetcherResults } = await callLoadersAndMaybeResolveData(dsMatches, revalidatingFetchers, revalidationRequest, nextLocation, scopedContext, "fetcher");
|
|
893
972
|
if (abortController.signal.aborted) {
|
|
894
973
|
if (fetchReloadIds.get(key) === loadId) fetchReloadIds.delete(key);
|
|
895
974
|
return;
|
|
@@ -911,13 +990,13 @@ function createRouter(init) {
|
|
|
911
990
|
let redirect = findRedirect(loaderResults);
|
|
912
991
|
if (redirect) {
|
|
913
992
|
state = getRedirectStateWithDoneFetcher(state);
|
|
914
|
-
return startRedirectNavigation(revalidationRequest, redirect.result, false, { preventScrollReset });
|
|
993
|
+
return startRedirectNavigation(revalidationRequest, redirect.result, false, "fetcher", { preventScrollReset });
|
|
915
994
|
}
|
|
916
995
|
redirect = findRedirect(fetcherResults);
|
|
917
996
|
if (redirect) {
|
|
918
997
|
fetchRedirectIds.add(redirect.key);
|
|
919
998
|
state = getRedirectStateWithDoneFetcher(state);
|
|
920
|
-
return startRedirectNavigation(revalidationRequest, redirect.result, false, { preventScrollReset });
|
|
999
|
+
return startRedirectNavigation(revalidationRequest, redirect.result, false, "fetcher", { preventScrollReset });
|
|
921
1000
|
}
|
|
922
1001
|
let finalFetchers = new Map(state.fetchers);
|
|
923
1002
|
if (fetcherIsMounted) finalFetchers.set(key, getDoneFetcher(actionResult.data));
|
|
@@ -941,26 +1020,36 @@ function createRouter(init) {
|
|
|
941
1020
|
isRevalidationRequired = false;
|
|
942
1021
|
}
|
|
943
1022
|
}
|
|
944
|
-
async function handleFetcherLoader(key,
|
|
1023
|
+
async function handleFetcherLoader(key, loadMatch, matches, scopedContext, flushSync, preventScrollReset, submission) {
|
|
1024
|
+
let { routeId, path } = loadMatch;
|
|
945
1025
|
let existingFetcher = state.fetchers.get(key);
|
|
946
1026
|
updateFetcherState(key, getLoadingFetcher(submission, existingFetcher ? existingFetcher.data : void 0), { flushSync });
|
|
947
1027
|
let abortController = new AbortController();
|
|
1028
|
+
if (future.unstable_customRouteDiscovery) fetchControllers.set(key, abortController);
|
|
948
1029
|
let fetchRequest = createClientSideRequest(init.history, path, abortController.signal);
|
|
949
|
-
if (
|
|
1030
|
+
if (loadMatch.isDiscovering) {
|
|
950
1031
|
let discoverResult = await discoverRoutes(matches, new URL(fetchRequest.url).pathname, fetchRequest.signal, key);
|
|
951
|
-
if (discoverResult.type === "aborted") return;
|
|
952
|
-
else if (discoverResult.type === "
|
|
1032
|
+
if (future.unstable_customRouteDiscovery && fetchRequest.signal.aborted || discoverResult.type === "aborted") return;
|
|
1033
|
+
else if (discoverResult.type === "cancelled") {
|
|
1034
|
+
fetchControllers.delete(key);
|
|
1035
|
+
fetchLoadMatches.delete(key);
|
|
1036
|
+
updateFetcherState(key, getDoneFetcher(existingFetcher?.data), { flushSync });
|
|
1037
|
+
return;
|
|
1038
|
+
} else if (discoverResult.type === "error") {
|
|
953
1039
|
setFetcherError(key, routeId, discoverResult.error, { flushSync });
|
|
954
1040
|
return;
|
|
955
1041
|
} else if (!discoverResult.matches) {
|
|
956
1042
|
setFetcherError(key, routeId, getInternalRouterError(404, { pathname: path }), { flushSync });
|
|
957
1043
|
return;
|
|
958
|
-
} else
|
|
1044
|
+
} else {
|
|
1045
|
+
matches = discoverResult.matches;
|
|
1046
|
+
loadMatch.isDiscovering = false;
|
|
1047
|
+
}
|
|
959
1048
|
}
|
|
960
1049
|
let match = getTargetMatch(matches, path);
|
|
961
1050
|
fetchControllers.set(key, abortController);
|
|
962
1051
|
let originatingLoadId = incrementingLoadId;
|
|
963
|
-
let results = await callDataStrategy(fetchRequest, path, getTargetedDataStrategyMatches(mapRouteProperties, manifest, fetchRequest, path, matches, match, hydrationRouteProperties, scopedContext), scopedContext, key);
|
|
1052
|
+
let results = await callDataStrategy(fetchRequest, path, getTargetedDataStrategyMatches(mapRouteProperties, manifest, fetchRequest, path, matches, match, hydrationRouteProperties, scopedContext), scopedContext, key, "fetcher");
|
|
964
1053
|
let result = results[match.route.id];
|
|
965
1054
|
if (!result) {
|
|
966
1055
|
for (let match of matches) if (results[match.route.id]) {
|
|
@@ -979,7 +1068,7 @@ function createRouter(init) {
|
|
|
979
1068
|
return;
|
|
980
1069
|
} else {
|
|
981
1070
|
fetchRedirectIds.add(key);
|
|
982
|
-
await startRedirectNavigation(fetchRequest, result, false, { preventScrollReset });
|
|
1071
|
+
await startRedirectNavigation(fetchRequest, result, false, "fetcher", { preventScrollReset });
|
|
983
1072
|
return;
|
|
984
1073
|
}
|
|
985
1074
|
if (isErrorResult(result)) {
|
|
@@ -1007,7 +1096,7 @@ function createRouter(init) {
|
|
|
1007
1096
|
* actually touch history until we've processed redirects, so we just use
|
|
1008
1097
|
* the history action from the original navigation (PUSH or REPLACE).
|
|
1009
1098
|
*/
|
|
1010
|
-
async function startRedirectNavigation(request, redirect, isNavigation, { submission, fetcherSubmission, preventScrollReset, replace } = {}) {
|
|
1099
|
+
async function startRedirectNavigation(request, redirect, isNavigation, dataStrategyInitiator, { submission, fetcherSubmission, preventScrollReset, replace } = {}) {
|
|
1011
1100
|
if (!isNavigation) {
|
|
1012
1101
|
pendingPopstateNavigationDfd?.resolve();
|
|
1013
1102
|
pendingPopstateNavigationDfd = null;
|
|
@@ -1044,20 +1133,22 @@ function createRouter(init) {
|
|
|
1044
1133
|
formAction: location
|
|
1045
1134
|
},
|
|
1046
1135
|
preventScrollReset: preventScrollReset || pendingPreventScrollReset,
|
|
1047
|
-
enableViewTransition: isNavigation ? pendingViewTransitionEnabled : void 0
|
|
1136
|
+
enableViewTransition: isNavigation ? pendingViewTransitionEnabled : void 0,
|
|
1137
|
+
dataStrategyInitiator
|
|
1048
1138
|
});
|
|
1049
1139
|
else await startNavigation(redirectNavigationType, redirectLocation, {
|
|
1050
1140
|
overrideNavigation: getLoadingNavigation(redirectLocation, [], redirectNavigationType, submission),
|
|
1051
1141
|
fetcherSubmission,
|
|
1052
1142
|
preventScrollReset: preventScrollReset || pendingPreventScrollReset,
|
|
1053
|
-
enableViewTransition: isNavigation ? pendingViewTransitionEnabled : void 0
|
|
1143
|
+
enableViewTransition: isNavigation ? pendingViewTransitionEnabled : void 0,
|
|
1144
|
+
dataStrategyInitiator
|
|
1054
1145
|
});
|
|
1055
1146
|
}
|
|
1056
|
-
async function callDataStrategy(request, path, matches, scopedContext, fetcherKey) {
|
|
1147
|
+
async function callDataStrategy(request, path, matches, scopedContext, fetcherKey, initiator, navigationType = null) {
|
|
1057
1148
|
let results;
|
|
1058
1149
|
let dataResults = {};
|
|
1059
1150
|
try {
|
|
1060
|
-
results = await callDataStrategyImpl(dataStrategyImpl, request, path, matches, fetcherKey, scopedContext, false);
|
|
1151
|
+
results = await callDataStrategyImpl(dataStrategyImpl, request, path, matches, fetcherKey, initiator, scopedContext, false, navigationType);
|
|
1061
1152
|
} catch (e) {
|
|
1062
1153
|
matches.filter((m) => m.shouldLoad).forEach((m) => {
|
|
1063
1154
|
dataResults[m.route.id] = {
|
|
@@ -1084,11 +1175,11 @@ function createRouter(init) {
|
|
|
1084
1175
|
} else dataResults[routeId] = await convertDataStrategyResultToDataResult(result);
|
|
1085
1176
|
return dataResults;
|
|
1086
1177
|
}
|
|
1087
|
-
async function callLoadersAndMaybeResolveData(matches, fetchersToLoad, request, location, scopedContext) {
|
|
1088
|
-
let loaderResultsPromise = callDataStrategy(request, location, matches, scopedContext, null);
|
|
1178
|
+
async function callLoadersAndMaybeResolveData(matches, fetchersToLoad, request, location, scopedContext, initiator, navigationType = null) {
|
|
1179
|
+
let loaderResultsPromise = callDataStrategy(request, location, matches, scopedContext, null, initiator, navigationType);
|
|
1089
1180
|
let fetcherResultsPromise = Promise.all(fetchersToLoad.map(async (f) => {
|
|
1090
1181
|
if (f.matches && f.match && f.request && f.controller) {
|
|
1091
|
-
let result = (await callDataStrategy(f.request, f.path, f.matches, scopedContext, f.key))[f.match.route.id];
|
|
1182
|
+
let result = (await callDataStrategy(f.request, f.path, f.matches, scopedContext, f.key, initiator, navigationType))[f.match.route.id];
|
|
1092
1183
|
return { [f.key]: result };
|
|
1093
1184
|
} else return Promise.resolve({ [f.key]: {
|
|
1094
1185
|
type: "error",
|
|
@@ -1102,7 +1193,8 @@ function createRouter(init) {
|
|
|
1102
1193
|
}
|
|
1103
1194
|
function interruptActiveLoads() {
|
|
1104
1195
|
isRevalidationRequired = true;
|
|
1105
|
-
fetchLoadMatches.forEach((
|
|
1196
|
+
fetchLoadMatches.forEach((loadMatch, key) => {
|
|
1197
|
+
if (future.unstable_customRouteDiscovery && loadMatch.isDiscovering) return;
|
|
1106
1198
|
if (fetchControllers.has(key)) cancelledFetcherLoads.add(key);
|
|
1107
1199
|
abortFetcher(key);
|
|
1108
1200
|
});
|
|
@@ -1128,6 +1220,8 @@ function createRouter(init) {
|
|
|
1128
1220
|
}
|
|
1129
1221
|
function resetFetcher(key, opts) {
|
|
1130
1222
|
abortFetcher(key, opts?.reason);
|
|
1223
|
+
fetchLoadMatches.delete(key);
|
|
1224
|
+
cancelledFetcherLoads.delete(key);
|
|
1131
1225
|
updateFetcherState(key, getDoneFetcher(null));
|
|
1132
1226
|
}
|
|
1133
1227
|
function deleteFetcher(fetchers, key) {
|
|
@@ -1264,16 +1358,15 @@ function createRouter(init) {
|
|
|
1264
1358
|
}
|
|
1265
1359
|
return null;
|
|
1266
1360
|
}
|
|
1267
|
-
function checkFogOfWar(matches,
|
|
1361
|
+
function checkFogOfWar(matches, pathname) {
|
|
1268
1362
|
if (init.patchRoutesOnNavigation) {
|
|
1269
|
-
let activeBranches = dataRoutes.branches;
|
|
1270
1363
|
if (!matches) return {
|
|
1271
1364
|
active: true,
|
|
1272
|
-
matches:
|
|
1365
|
+
matches: dataRouteMatcher.match(pathname, true) || []
|
|
1273
1366
|
};
|
|
1274
1367
|
else if (Object.keys(matches[0].params).length > 0) return {
|
|
1275
1368
|
active: true,
|
|
1276
|
-
matches:
|
|
1369
|
+
matches: dataRouteMatcher.match(pathname, true)
|
|
1277
1370
|
};
|
|
1278
1371
|
}
|
|
1279
1372
|
return {
|
|
@@ -1301,6 +1394,10 @@ function createRouter(init) {
|
|
|
1301
1394
|
}
|
|
1302
1395
|
});
|
|
1303
1396
|
} catch (e) {
|
|
1397
|
+
if (future.unstable_customRouteDiscovery) {
|
|
1398
|
+
if (signal.aborted) return { type: "aborted" };
|
|
1399
|
+
if (e instanceof DiscoveryCancelledError) return { type: "cancelled" };
|
|
1400
|
+
}
|
|
1304
1401
|
return {
|
|
1305
1402
|
type: "error",
|
|
1306
1403
|
error: e,
|
|
@@ -1308,21 +1405,20 @@ function createRouter(init) {
|
|
|
1308
1405
|
};
|
|
1309
1406
|
}
|
|
1310
1407
|
if (signal.aborted) return { type: "aborted" };
|
|
1311
|
-
let
|
|
1312
|
-
let newMatches = matchRoutesImpl(dataRoutes.activeRoutes, pathname, basename, false, activeBranches);
|
|
1408
|
+
let newMatches = dataRouteMatcher.match(pathname);
|
|
1313
1409
|
let newPartialMatches = null;
|
|
1314
1410
|
if (newMatches) if (Object.keys(newMatches[0].params).length === 0) return {
|
|
1315
1411
|
type: "success",
|
|
1316
1412
|
matches: newMatches
|
|
1317
1413
|
};
|
|
1318
1414
|
else {
|
|
1319
|
-
newPartialMatches =
|
|
1415
|
+
newPartialMatches = dataRouteMatcher.match(pathname, true);
|
|
1320
1416
|
if (!(newPartialMatches && partialMatches.length < newPartialMatches.length && compareMatches(partialMatches, newPartialMatches.slice(0, partialMatches.length)))) return {
|
|
1321
1417
|
type: "success",
|
|
1322
1418
|
matches: newMatches
|
|
1323
1419
|
};
|
|
1324
1420
|
}
|
|
1325
|
-
if (!newPartialMatches) newPartialMatches =
|
|
1421
|
+
if (!newPartialMatches) newPartialMatches = dataRouteMatcher.match(pathname, true);
|
|
1326
1422
|
if (!newPartialMatches || compareMatches(partialMatches, newPartialMatches)) return {
|
|
1327
1423
|
type: "success",
|
|
1328
1424
|
matches: null
|
|
@@ -1354,8 +1450,8 @@ function createRouter(init) {
|
|
|
1354
1450
|
get routes() {
|
|
1355
1451
|
return dataRoutes.stableRoutes;
|
|
1356
1452
|
},
|
|
1357
|
-
|
|
1358
|
-
return
|
|
1453
|
+
match(locationArg) {
|
|
1454
|
+
return dataRouteMatcher.match(locationArg);
|
|
1359
1455
|
},
|
|
1360
1456
|
get manifest() {
|
|
1361
1457
|
return manifest;
|
|
@@ -1424,7 +1520,7 @@ function createStaticHandler(routes, opts) {
|
|
|
1424
1520
|
let basename = (opts ? opts.basename : null) || "/";
|
|
1425
1521
|
let _mapRouteProperties = opts?.mapRouteProperties;
|
|
1426
1522
|
let mapRouteProperties = _mapRouteProperties ? _mapRouteProperties : () => ({});
|
|
1427
|
-
({ ...opts?.future });
|
|
1523
|
+
let dataRouteMatcher = createDataRouteMatcher({ ...opts?.future }, basename);
|
|
1428
1524
|
if (opts?.instrumentations) {
|
|
1429
1525
|
let instrumentations = opts.instrumentations;
|
|
1430
1526
|
mapRouteProperties = (route) => {
|
|
@@ -1435,7 +1531,8 @@ function createStaticHandler(routes, opts) {
|
|
|
1435
1531
|
};
|
|
1436
1532
|
}
|
|
1437
1533
|
let dataRoutes = convertRoutesToDataRoutes(routes, mapRouteProperties, void 0, manifest);
|
|
1438
|
-
|
|
1534
|
+
dataRouteMatcher.update(dataRoutes);
|
|
1535
|
+
let match = (locationArg) => dataRouteMatcher.match(locationArg);
|
|
1439
1536
|
/**
|
|
1440
1537
|
* The query() method is intended for document requests, in which we want to
|
|
1441
1538
|
* call an optional action and potentially multiple loaders for all nested
|
|
@@ -1466,7 +1563,7 @@ function createStaticHandler(routes, opts) {
|
|
|
1466
1563
|
let normalizePathImpl = normalizePath || defaultNormalizePath;
|
|
1467
1564
|
let method = request.method;
|
|
1468
1565
|
let location = createLocation("", normalizePathImpl(request), null, "default");
|
|
1469
|
-
let matches =
|
|
1566
|
+
let matches = dataRouteMatcher.match(location);
|
|
1470
1567
|
requestContext = requestContext != null ? requestContext : new RouterContextProvider();
|
|
1471
1568
|
if (!isValidMethod(method) && method !== "HEAD") {
|
|
1472
1569
|
let error = getInternalRouterError(405, { method });
|
|
@@ -1480,7 +1577,8 @@ function createStaticHandler(routes, opts) {
|
|
|
1480
1577
|
errors: { [route.id]: error },
|
|
1481
1578
|
statusCode: error.status,
|
|
1482
1579
|
loaderHeaders: {},
|
|
1483
|
-
actionHeaders: {}
|
|
1580
|
+
actionHeaders: {},
|
|
1581
|
+
_match: match
|
|
1484
1582
|
};
|
|
1485
1583
|
return generateMiddlewareResponse ? generateMiddlewareResponse(() => Promise.resolve(staticContext)) : staticContext;
|
|
1486
1584
|
} else if (!matches) {
|
|
@@ -1495,7 +1593,8 @@ function createStaticHandler(routes, opts) {
|
|
|
1495
1593
|
errors: { [route.id]: error },
|
|
1496
1594
|
statusCode: error.status,
|
|
1497
1595
|
loaderHeaders: {},
|
|
1498
|
-
actionHeaders: {}
|
|
1596
|
+
actionHeaders: {},
|
|
1597
|
+
_match: match
|
|
1499
1598
|
};
|
|
1500
1599
|
return generateMiddlewareResponse ? generateMiddlewareResponse(() => Promise.resolve(staticContext)) : staticContext;
|
|
1501
1600
|
}
|
|
@@ -1518,7 +1617,8 @@ function createStaticHandler(routes, opts) {
|
|
|
1518
1617
|
renderedStaticContext = {
|
|
1519
1618
|
location,
|
|
1520
1619
|
basename,
|
|
1521
|
-
...result
|
|
1620
|
+
...result,
|
|
1621
|
+
_match: match
|
|
1522
1622
|
};
|
|
1523
1623
|
return renderedStaticContext;
|
|
1524
1624
|
});
|
|
@@ -1544,7 +1644,8 @@ function createStaticHandler(routes, opts) {
|
|
|
1544
1644
|
errors: { [skipLoaderErrorBubbling ? routeId : findNearestBoundary(matches, matches.find((m) => m.route.id === routeId || m.route.loader)?.route.id || routeId).route.id]: error },
|
|
1545
1645
|
statusCode: isRouteErrorResponse(error) ? error.status : 500,
|
|
1546
1646
|
actionHeaders: {},
|
|
1547
|
-
loaderHeaders: {}
|
|
1647
|
+
loaderHeaders: {},
|
|
1648
|
+
_match: match
|
|
1548
1649
|
};
|
|
1549
1650
|
return generateMiddlewareResponse(() => Promise.resolve(staticContext));
|
|
1550
1651
|
}
|
|
@@ -1561,7 +1662,8 @@ function createStaticHandler(routes, opts) {
|
|
|
1561
1662
|
return {
|
|
1562
1663
|
location,
|
|
1563
1664
|
basename,
|
|
1564
|
-
...result
|
|
1665
|
+
...result,
|
|
1666
|
+
_match: match
|
|
1565
1667
|
};
|
|
1566
1668
|
}
|
|
1567
1669
|
/**
|
|
@@ -1594,7 +1696,7 @@ function createStaticHandler(routes, opts) {
|
|
|
1594
1696
|
let normalizePathImpl = normalizePath || defaultNormalizePath;
|
|
1595
1697
|
let method = request.method;
|
|
1596
1698
|
let location = createLocation("", normalizePathImpl(request), null, "default");
|
|
1597
|
-
let matches =
|
|
1699
|
+
let matches = dataRouteMatcher.match(location);
|
|
1598
1700
|
requestContext = requestContext != null ? requestContext : new RouterContextProvider();
|
|
1599
1701
|
if (!isValidMethod(method) && method !== "HEAD" && method !== "OPTIONS") throw getInternalRouterError(405, { method });
|
|
1600
1702
|
else if (!matches) throw getInternalRouterError(404, { pathname: location.pathname });
|
|
@@ -1756,7 +1858,7 @@ function createStaticHandler(routes, opts) {
|
|
|
1756
1858
|
};
|
|
1757
1859
|
}
|
|
1758
1860
|
async function callDataStrategy(request, location, matches, isRouteRequest, requestContext, dataStrategy) {
|
|
1759
|
-
let results = await callDataStrategyImpl(dataStrategy || defaultDataStrategy, request, location, matches, null, requestContext, true);
|
|
1861
|
+
let results = await callDataStrategyImpl(dataStrategy || defaultDataStrategy, request, location, matches, null, "static", requestContext, true);
|
|
1760
1862
|
let dataResults = {};
|
|
1761
1863
|
await Promise.all(matches.map(async (match) => {
|
|
1762
1864
|
if (!(match.route.id in results)) return;
|
|
@@ -1775,7 +1877,7 @@ function createStaticHandler(routes, opts) {
|
|
|
1775
1877
|
}
|
|
1776
1878
|
return {
|
|
1777
1879
|
dataRoutes,
|
|
1778
|
-
|
|
1880
|
+
match,
|
|
1779
1881
|
query,
|
|
1780
1882
|
queryRoute
|
|
1781
1883
|
};
|
|
@@ -1936,7 +2038,7 @@ function normalizeNavigateOptions(isFetcher, path, opts) {
|
|
|
1936
2038
|
submission
|
|
1937
2039
|
};
|
|
1938
2040
|
}
|
|
1939
|
-
function getMatchesToLoad(request, scopedContext, mapRouteProperties, manifest, history, state, matches, submission, location, lazyRoutePropertiesToSkip, initialHydration, isRevalidationRequired, cancelledFetcherLoads, fetchersQueuedForDeletion, fetchLoadMatches, fetchRedirectIds,
|
|
2041
|
+
function getMatchesToLoad(request, scopedContext, mapRouteProperties, manifest, history, state, matches, submission, location, lazyRoutePropertiesToSkip, initialHydration, isRevalidationRequired, cancelledFetcherLoads, fetchersQueuedForDeletion, fetchLoadMatches, fetchRedirectIds, dataRouteMatcher, pendingActionResult, callSiteDefaultShouldRevalidate) {
|
|
1940
2042
|
let actionResult = pendingActionResult ? isErrorResult(pendingActionResult[1]) ? pendingActionResult[1].error : pendingActionResult[1].data : void 0;
|
|
1941
2043
|
let currentUrl = history.createURL(state.location);
|
|
1942
2044
|
let nextUrl = history.createURL(location);
|
|
@@ -1986,12 +2088,11 @@ function getMatchesToLoad(request, scopedContext, mapRouteProperties, manifest,
|
|
|
1986
2088
|
});
|
|
1987
2089
|
let revalidatingFetchers = [];
|
|
1988
2090
|
fetchLoadMatches.forEach((f, key) => {
|
|
1989
|
-
if (initialHydration || !matches.some((m) => m.route.id === f.routeId) || fetchersQueuedForDeletion.has(key)) return;
|
|
2091
|
+
if (initialHydration || !matches.some((m) => m.route.id === f.routeId) || fetchersQueuedForDeletion.has(key) || f.isDiscovering) return;
|
|
1990
2092
|
let fetcher = state.fetchers.get(key);
|
|
1991
2093
|
let isMidInitialLoad = fetcher && fetcher.state !== "idle" && fetcher.data === void 0;
|
|
1992
|
-
let fetcherMatches =
|
|
2094
|
+
let fetcherMatches = dataRouteMatcher.match(f.path);
|
|
1993
2095
|
if (!fetcherMatches) {
|
|
1994
|
-
if (hasPatchRoutesOnNavigation && isMidInitialLoad) return;
|
|
1995
2096
|
revalidatingFetchers.push({
|
|
1996
2097
|
key,
|
|
1997
2098
|
routeId: f.routeId,
|
|
@@ -2398,7 +2499,7 @@ function getTargetedDataStrategyMatches(mapRouteProperties, manifest, request, p
|
|
|
2398
2499
|
return getDataStrategyMatch(mapRouteProperties, manifest, request, path, getRoutePattern(matches), match, lazyRoutePropertiesToSkip, scopedContext, true, shouldRevalidateArgs);
|
|
2399
2500
|
});
|
|
2400
2501
|
}
|
|
2401
|
-
async function callDataStrategyImpl(dataStrategyImpl, request, path, matches, fetcherKey, scopedContext, isStaticHandler) {
|
|
2502
|
+
async function callDataStrategyImpl(dataStrategyImpl, request, path, matches, fetcherKey, initiator, scopedContext, isStaticHandler, navigationType = null) {
|
|
2402
2503
|
if (matches.some((m) => m._lazyPromises?.middleware)) await Promise.all(matches.map((m) => m._lazyPromises?.middleware));
|
|
2403
2504
|
let dataStrategyArgs = {
|
|
2404
2505
|
request,
|
|
@@ -2406,7 +2507,9 @@ async function callDataStrategyImpl(dataStrategyImpl, request, path, matches, fe
|
|
|
2406
2507
|
pattern: getRoutePattern(matches),
|
|
2407
2508
|
params: matches[0].params,
|
|
2408
2509
|
context: scopedContext,
|
|
2409
|
-
matches
|
|
2510
|
+
matches,
|
|
2511
|
+
unstable_initiator: initiator,
|
|
2512
|
+
unstable_navigationType: initiator === "navigation" ? navigationType : null
|
|
2410
2513
|
};
|
|
2411
2514
|
let runClientMiddleware = isStaticHandler ? () => {
|
|
2412
2515
|
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`");
|
|
@@ -2717,12 +2820,16 @@ function mergeLoaderData(loaderData, newLoaderData, matches, errors) {
|
|
|
2717
2820
|
merged[k] = v;
|
|
2718
2821
|
return merged;
|
|
2719
2822
|
}, {});
|
|
2823
|
+
let preservedCount = 0;
|
|
2720
2824
|
for (let match of matches) {
|
|
2721
2825
|
let id = match.route.id;
|
|
2722
|
-
if (!newLoaderData.hasOwnProperty(id) && loaderData.hasOwnProperty(id) && match.route.loader)
|
|
2826
|
+
if (!newLoaderData.hasOwnProperty(id) && loaderData.hasOwnProperty(id) && match.route.loader) {
|
|
2827
|
+
mergedLoaderData[id] = loaderData[id];
|
|
2828
|
+
preservedCount++;
|
|
2829
|
+
}
|
|
2723
2830
|
if (errors && errors.hasOwnProperty(id)) break;
|
|
2724
2831
|
}
|
|
2725
|
-
return mergedLoaderData;
|
|
2832
|
+
return Object.keys(newLoaderData).length === 0 && preservedCount === Object.keys(loaderData).length ? loaderData : mergedLoaderData;
|
|
2726
2833
|
}
|
|
2727
2834
|
function getActionDataForCommit(pendingActionResult) {
|
|
2728
2835
|
if (!pendingActionResult) return {};
|
|
@@ -2999,4 +3106,4 @@ function createDeferred() {
|
|
|
2999
3106
|
};
|
|
3000
3107
|
}
|
|
3001
3108
|
//#endregion
|
|
3002
|
-
export { IDLE_BLOCKER, IDLE_FETCHER, IDLE_NAVIGATION, createRouter, createStaticHandler, getStaticContextFromError, hasInvalidProtocol, isDataWithResponseInit, isMutationMethod, isRedirectResponse, isRedirectStatusCode, isResponse };
|
|
3109
|
+
export { IDLE_BLOCKER, IDLE_FETCHER, IDLE_NAVIGATION, clientErrors, createDataRouteMatcher, createRouter, createStaticHandler, getStaticContextFromError, hasInvalidProtocol, isDataWithResponseInit, isMutationMethod, isRedirectResponse, isRedirectStatusCode, isResponse };
|