@tanstack/router-core 1.121.0-alpha.27 → 1.121.0-alpha.28
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/dist/cjs/Matches.cjs.map +1 -1
- package/dist/cjs/Matches.d.cts +31 -1
- package/dist/cjs/RouterProvider.d.cts +2 -1
- package/dist/cjs/defer.cjs +1 -1
- package/dist/cjs/defer.cjs.map +1 -1
- package/dist/cjs/global.d.cts +7 -0
- package/dist/cjs/index.cjs +1 -2
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +6 -6
- package/dist/cjs/link.cjs.map +1 -1
- package/dist/cjs/link.d.cts +12 -0
- package/dist/cjs/lru-cache.cjs +62 -0
- package/dist/cjs/lru-cache.cjs.map +1 -0
- package/dist/cjs/lru-cache.d.cts +5 -0
- package/dist/cjs/not-found.cjs +1 -1
- package/dist/cjs/not-found.cjs.map +1 -1
- package/dist/cjs/path.cjs +316 -148
- package/dist/cjs/path.cjs.map +1 -1
- package/dist/cjs/path.d.cts +18 -24
- package/dist/cjs/qss.cjs.map +1 -1
- package/dist/cjs/redirect.cjs +3 -0
- package/dist/cjs/redirect.cjs.map +1 -1
- package/dist/cjs/route.cjs +6 -12
- package/dist/cjs/route.cjs.map +1 -1
- package/dist/cjs/route.d.cts +29 -9
- package/dist/cjs/router.cjs +453 -272
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/router.d.cts +55 -85
- package/dist/cjs/scroll-restoration.cjs +20 -13
- package/dist/cjs/scroll-restoration.cjs.map +1 -1
- package/dist/cjs/scroll-restoration.d.cts +9 -1
- package/dist/cjs/searchMiddleware.cjs.map +1 -1
- package/dist/cjs/searchParams.cjs.map +1 -1
- package/dist/cjs/ssr/client.cjs +10 -0
- package/dist/cjs/ssr/client.cjs.map +1 -0
- package/dist/cjs/ssr/client.d.cts +5 -0
- package/dist/cjs/ssr/createRequestHandler.cjs +50 -0
- package/dist/cjs/ssr/createRequestHandler.cjs.map +1 -0
- package/dist/cjs/ssr/createRequestHandler.d.cts +9 -0
- package/dist/cjs/ssr/handlerCallback.cjs +7 -0
- package/dist/cjs/ssr/handlerCallback.cjs.map +1 -0
- package/dist/cjs/ssr/handlerCallback.d.cts +9 -0
- package/dist/cjs/ssr/headers.cjs +39 -0
- package/dist/cjs/ssr/headers.cjs.map +1 -0
- package/dist/cjs/ssr/headers.d.cts +5 -0
- package/dist/cjs/ssr/json.cjs +14 -0
- package/dist/cjs/ssr/json.cjs.map +1 -0
- package/dist/cjs/ssr/json.d.cts +4 -0
- package/dist/cjs/ssr/seroval-plugins.cjs +34 -0
- package/dist/cjs/ssr/seroval-plugins.cjs.map +1 -0
- package/dist/cjs/ssr/seroval-plugins.d.cts +10 -0
- package/dist/cjs/ssr/server.cjs +13 -0
- package/dist/cjs/ssr/server.cjs.map +1 -0
- package/dist/cjs/ssr/server.d.cts +6 -0
- package/dist/cjs/ssr/ssr-client.cjs +159 -0
- package/dist/cjs/ssr/ssr-client.cjs.map +1 -0
- package/dist/cjs/ssr/ssr-client.d.cts +29 -0
- package/dist/cjs/ssr/ssr-server.cjs +107 -0
- package/dist/cjs/ssr/ssr-server.cjs.map +1 -0
- package/dist/cjs/ssr/ssr-server.d.cts +18 -0
- package/dist/cjs/ssr/transformStreamWithRouter.cjs +183 -0
- package/dist/cjs/ssr/transformStreamWithRouter.cjs.map +1 -0
- package/dist/cjs/ssr/transformStreamWithRouter.d.cts +6 -0
- package/dist/cjs/ssr/tsrScript.cjs +4 -0
- package/dist/cjs/ssr/tsrScript.cjs.map +1 -0
- package/dist/cjs/ssr/tsrScript.d.cts +0 -0
- package/dist/cjs/utils.cjs +7 -25
- package/dist/cjs/utils.cjs.map +1 -1
- package/dist/cjs/utils.d.cts +1 -6
- package/dist/esm/Matches.d.ts +31 -1
- package/dist/esm/Matches.js.map +1 -1
- package/dist/esm/RouterProvider.d.ts +2 -1
- package/dist/esm/defer.js +1 -1
- package/dist/esm/defer.js.map +1 -1
- package/dist/esm/global.d.ts +7 -0
- package/dist/esm/index.d.ts +6 -6
- package/dist/esm/index.js +2 -3
- package/dist/esm/link.d.ts +12 -0
- package/dist/esm/link.js.map +1 -1
- package/dist/esm/lru-cache.d.ts +5 -0
- package/dist/esm/lru-cache.js +62 -0
- package/dist/esm/lru-cache.js.map +1 -0
- package/dist/esm/not-found.js +1 -1
- package/dist/esm/not-found.js.map +1 -1
- package/dist/esm/path.d.ts +18 -24
- package/dist/esm/path.js +316 -148
- package/dist/esm/path.js.map +1 -1
- package/dist/esm/qss.js.map +1 -1
- package/dist/esm/redirect.js +3 -0
- package/dist/esm/redirect.js.map +1 -1
- package/dist/esm/route.d.ts +29 -9
- package/dist/esm/route.js +6 -12
- package/dist/esm/route.js.map +1 -1
- package/dist/esm/router.d.ts +55 -85
- package/dist/esm/router.js +462 -281
- package/dist/esm/router.js.map +1 -1
- package/dist/esm/scroll-restoration.d.ts +9 -1
- package/dist/esm/scroll-restoration.js +20 -13
- package/dist/esm/scroll-restoration.js.map +1 -1
- package/dist/esm/searchMiddleware.js.map +1 -1
- package/dist/esm/searchParams.js.map +1 -1
- package/dist/esm/ssr/client.d.ts +5 -0
- package/dist/esm/ssr/client.js +10 -0
- package/dist/esm/ssr/client.js.map +1 -0
- package/dist/esm/ssr/createRequestHandler.d.ts +9 -0
- package/dist/esm/ssr/createRequestHandler.js +50 -0
- package/dist/esm/ssr/createRequestHandler.js.map +1 -0
- package/dist/esm/ssr/handlerCallback.d.ts +9 -0
- package/dist/esm/ssr/handlerCallback.js +7 -0
- package/dist/esm/ssr/handlerCallback.js.map +1 -0
- package/dist/esm/ssr/headers.d.ts +5 -0
- package/dist/esm/ssr/headers.js +39 -0
- package/dist/esm/ssr/headers.js.map +1 -0
- package/dist/esm/ssr/json.d.ts +4 -0
- package/dist/esm/ssr/json.js +14 -0
- package/dist/esm/ssr/json.js.map +1 -0
- package/dist/esm/ssr/seroval-plugins.d.ts +10 -0
- package/dist/esm/ssr/seroval-plugins.js +34 -0
- package/dist/esm/ssr/seroval-plugins.js.map +1 -0
- package/dist/esm/ssr/server.d.ts +6 -0
- package/dist/esm/ssr/server.js +13 -0
- package/dist/esm/ssr/server.js.map +1 -0
- package/dist/esm/ssr/ssr-client.d.ts +29 -0
- package/dist/esm/ssr/ssr-client.js +159 -0
- package/dist/esm/ssr/ssr-client.js.map +1 -0
- package/dist/esm/ssr/ssr-server.d.ts +18 -0
- package/dist/esm/ssr/ssr-server.js +107 -0
- package/dist/esm/ssr/ssr-server.js.map +1 -0
- package/dist/esm/ssr/transformStreamWithRouter.d.ts +6 -0
- package/dist/esm/ssr/transformStreamWithRouter.js +183 -0
- package/dist/esm/ssr/transformStreamWithRouter.js.map +1 -0
- package/dist/esm/ssr/tsrScript.d.ts +0 -0
- package/dist/esm/ssr/tsrScript.js +5 -0
- package/dist/esm/ssr/tsrScript.js.map +1 -0
- package/dist/esm/utils.d.ts +1 -6
- package/dist/esm/utils.js +8 -26
- package/dist/esm/utils.js.map +1 -1
- package/package.json +29 -2
- package/src/Matches.ts +40 -1
- package/src/RouterProvider.ts +2 -1
- package/src/global.ts +9 -0
- package/src/index.ts +12 -20
- package/src/link.ts +12 -0
- package/src/lru-cache.ts +68 -0
- package/src/path.ts +424 -174
- package/src/redirect.ts +3 -0
- package/src/route.ts +44 -13
- package/src/router.ts +580 -312
- package/src/scroll-restoration.ts +30 -18
- package/src/ssr/client.ts +5 -0
- package/src/ssr/createRequestHandler.ts +74 -0
- package/src/ssr/handlerCallback.ts +15 -0
- package/src/ssr/headers.ts +51 -0
- package/src/ssr/json.ts +18 -0
- package/src/ssr/seroval-plugins.ts +43 -0
- package/src/ssr/server.ts +10 -0
- package/src/ssr/ssr-client.ts +242 -0
- package/src/ssr/ssr-server.ts +132 -0
- package/src/ssr/transformStreamWithRouter.ts +259 -0
- package/src/ssr/tsrScript.ts +7 -0
- package/src/utils.ts +10 -39
- package/src/vite-env.d.ts +4 -0
- package/dist/cjs/serializer.d.cts +0 -22
- package/dist/esm/serializer.d.ts +0 -22
- package/src/serializer.ts +0 -32
package/dist/esm/router.js
CHANGED
|
@@ -2,12 +2,13 @@ import { Store, batch } from "@tanstack/store";
|
|
|
2
2
|
import { createMemoryHistory, createBrowserHistory, parseHref } from "@tanstack/history";
|
|
3
3
|
import invariant from "tiny-invariant";
|
|
4
4
|
import { pick, createControlledPromise, deepEqual, replaceEqualDeep, last, functionalUpdate } from "./utils.js";
|
|
5
|
-
import { trimPath, resolvePath, cleanPath, matchPathname, trimPathRight, interpolatePath, joinPaths, trimPathLeft, parsePathname } from "./path.js";
|
|
5
|
+
import { trimPath, resolvePath, cleanPath, matchPathname, trimPathRight, interpolatePath, joinPaths, trimPathLeft, parsePathname, SEGMENT_TYPE_PARAM, SEGMENT_TYPE_OPTIONAL_PARAM, SEGMENT_TYPE_WILDCARD, SEGMENT_TYPE_PATHNAME } from "./path.js";
|
|
6
6
|
import { isNotFound } from "./not-found.js";
|
|
7
7
|
import { setupScrollRestoration } from "./scroll-restoration.js";
|
|
8
8
|
import { defaultParseSearch, defaultStringifySearch } from "./searchParams.js";
|
|
9
9
|
import { rootRouteId } from "./root.js";
|
|
10
|
-
import { isRedirect } from "./redirect.js";
|
|
10
|
+
import { redirect, isRedirect } from "./redirect.js";
|
|
11
|
+
import { createLRUCache } from "./lru-cache.js";
|
|
11
12
|
function defaultSerializeError(err) {
|
|
12
13
|
if (err instanceof Error) {
|
|
13
14
|
const obj = {
|
|
@@ -26,9 +27,9 @@ function defaultSerializeError(err) {
|
|
|
26
27
|
function getLocationChangeInfo(routerState) {
|
|
27
28
|
const fromLocation = routerState.resolvedLocation;
|
|
28
29
|
const toLocation = routerState.location;
|
|
29
|
-
const pathChanged =
|
|
30
|
-
const hrefChanged =
|
|
31
|
-
const hashChanged =
|
|
30
|
+
const pathChanged = fromLocation?.pathname !== toLocation.pathname;
|
|
31
|
+
const hrefChanged = fromLocation?.href !== toLocation.href;
|
|
32
|
+
const hashChanged = fromLocation?.hash !== toLocation.hash;
|
|
32
33
|
return { fromLocation, toLocation, pathChanged, hrefChanged, hashChanged };
|
|
33
34
|
}
|
|
34
35
|
class RouterCore {
|
|
@@ -46,9 +47,7 @@ class RouterCore {
|
|
|
46
47
|
this.isScrollRestoring = false;
|
|
47
48
|
this.isScrollRestorationSetup = false;
|
|
48
49
|
this.startTransition = (fn) => fn();
|
|
49
|
-
this.isShell = false;
|
|
50
50
|
this.update = (newOptions) => {
|
|
51
|
-
var _a;
|
|
52
51
|
if (newOptions.notFoundRoute) {
|
|
53
52
|
console.warn(
|
|
54
53
|
"The notFoundRoute API is deprecated and will be removed in the next major version. See https://tanstack.com/router/v1/docs/framework/react/guide/not-found-errors#migrating-from-notfoundroute for more info."
|
|
@@ -96,22 +95,18 @@ class RouterCore {
|
|
|
96
95
|
});
|
|
97
96
|
setupScrollRestoration(this);
|
|
98
97
|
}
|
|
99
|
-
if (typeof window !== "undefined" && "CSS" in window && typeof
|
|
98
|
+
if (typeof window !== "undefined" && "CSS" in window && typeof window.CSS?.supports === "function") {
|
|
100
99
|
this.isViewTransitionTypesSupported = window.CSS.supports(
|
|
101
100
|
"selector(:active-view-transition-type(a)"
|
|
102
101
|
);
|
|
103
102
|
}
|
|
104
|
-
if (this.latestLocation.search.__TSS_SHELL) {
|
|
105
|
-
this.isShell = true;
|
|
106
|
-
}
|
|
107
103
|
};
|
|
108
104
|
this.buildRouteTree = () => {
|
|
109
105
|
const { routesById, routesByPath, flatRoutes } = processRouteTree({
|
|
110
106
|
routeTree: this.routeTree,
|
|
111
107
|
initRoute: (route, i) => {
|
|
112
108
|
route.init({
|
|
113
|
-
originalIndex: i
|
|
114
|
-
defaultSsr: this.options.defaultSsr
|
|
109
|
+
originalIndex: i
|
|
115
110
|
});
|
|
116
111
|
}
|
|
117
112
|
});
|
|
@@ -121,8 +116,7 @@ class RouterCore {
|
|
|
121
116
|
const notFoundRoute = this.options.notFoundRoute;
|
|
122
117
|
if (notFoundRoute) {
|
|
123
118
|
notFoundRoute.init({
|
|
124
|
-
originalIndex: 99999999999
|
|
125
|
-
defaultSsr: this.options.defaultSsr
|
|
119
|
+
originalIndex: 99999999999
|
|
126
120
|
});
|
|
127
121
|
this.routesById[notFoundRoute.id] = notFoundRoute;
|
|
128
122
|
}
|
|
@@ -156,10 +150,10 @@ class RouterCore {
|
|
|
156
150
|
return {
|
|
157
151
|
pathname,
|
|
158
152
|
searchStr,
|
|
159
|
-
search: replaceEqualDeep(previousLocation
|
|
153
|
+
search: replaceEqualDeep(previousLocation?.search, parsedSearch),
|
|
160
154
|
hash: hash.split("#").reverse()[0] ?? "",
|
|
161
155
|
href: `${pathname}${searchStr}${hash}`,
|
|
162
|
-
state: replaceEqualDeep(previousLocation
|
|
156
|
+
state: replaceEqualDeep(previousLocation?.state, state)
|
|
163
157
|
};
|
|
164
158
|
};
|
|
165
159
|
const location = parse(locationToParse ?? this.history.location);
|
|
@@ -167,6 +161,7 @@ class RouterCore {
|
|
|
167
161
|
if (__tempLocation && (!__tempKey || __tempKey === this.tempLocationKey)) {
|
|
168
162
|
const parsedTempLocation = parse(__tempLocation);
|
|
169
163
|
parsedTempLocation.state.key = location.state.key;
|
|
164
|
+
parsedTempLocation.state.__TSR_key = location.state.__TSR_key;
|
|
170
165
|
delete parsedTempLocation.state.__tempLocation;
|
|
171
166
|
return {
|
|
172
167
|
...parsedTempLocation,
|
|
@@ -181,7 +176,8 @@ class RouterCore {
|
|
|
181
176
|
base: from,
|
|
182
177
|
to: cleanPath(path),
|
|
183
178
|
trailingSlash: this.options.trailingSlash,
|
|
184
|
-
caseSensitive: this.options.caseSensitive
|
|
179
|
+
caseSensitive: this.options.caseSensitive,
|
|
180
|
+
parseCache: this.parsePathnameCache
|
|
185
181
|
});
|
|
186
182
|
return resolvedPath;
|
|
187
183
|
};
|
|
@@ -197,6 +193,7 @@ class RouterCore {
|
|
|
197
193
|
}
|
|
198
194
|
return this.matchRoutesInternal(pathnameOrNext, locationSearchOrOpts);
|
|
199
195
|
};
|
|
196
|
+
this.parsePathnameCache = createLRUCache(1e3);
|
|
200
197
|
this.getMatchedRoutes = (pathname, routePathname) => {
|
|
201
198
|
return getMatchedRoutes({
|
|
202
199
|
pathname,
|
|
@@ -205,50 +202,71 @@ class RouterCore {
|
|
|
205
202
|
caseSensitive: this.options.caseSensitive,
|
|
206
203
|
routesByPath: this.routesByPath,
|
|
207
204
|
routesById: this.routesById,
|
|
208
|
-
flatRoutes: this.flatRoutes
|
|
205
|
+
flatRoutes: this.flatRoutes,
|
|
206
|
+
parseCache: this.parsePathnameCache
|
|
209
207
|
});
|
|
210
208
|
};
|
|
211
209
|
this.cancelMatch = (id) => {
|
|
212
210
|
const match = this.getMatch(id);
|
|
213
211
|
if (!match) return;
|
|
214
212
|
match.abortController.abort();
|
|
215
|
-
|
|
213
|
+
this.updateMatch(id, (prev) => {
|
|
214
|
+
clearTimeout(prev.pendingTimeout);
|
|
215
|
+
return {
|
|
216
|
+
...prev,
|
|
217
|
+
pendingTimeout: void 0
|
|
218
|
+
};
|
|
219
|
+
});
|
|
216
220
|
};
|
|
217
221
|
this.cancelMatches = () => {
|
|
218
|
-
|
|
219
|
-
(_a = this.state.pendingMatches) == null ? void 0 : _a.forEach((match) => {
|
|
222
|
+
this.state.pendingMatches?.forEach((match) => {
|
|
220
223
|
this.cancelMatch(match.id);
|
|
221
224
|
});
|
|
222
225
|
};
|
|
223
226
|
this.buildLocation = (opts) => {
|
|
224
227
|
const build = (dest = {}) => {
|
|
225
|
-
var _a;
|
|
226
228
|
const currentLocation = dest._fromLocation || this.latestLocation;
|
|
227
|
-
const
|
|
229
|
+
const allCurrentLocationMatches = this.matchRoutes(currentLocation, {
|
|
228
230
|
_buildLocation: true
|
|
229
231
|
});
|
|
230
|
-
const lastMatch = last(
|
|
232
|
+
const lastMatch = last(allCurrentLocationMatches);
|
|
231
233
|
let fromPath = lastMatch.fullPath;
|
|
234
|
+
const toPath = dest.to ? this.resolvePathWithBase(fromPath, `${dest.to}`) : this.resolvePathWithBase(fromPath, ".");
|
|
235
|
+
const routeIsChanging = !!dest.to && !comparePaths(dest.to.toString(), fromPath) && !comparePaths(toPath, fromPath);
|
|
232
236
|
if (dest.unsafeRelative === "path") {
|
|
233
237
|
fromPath = currentLocation.pathname;
|
|
234
|
-
} else if (
|
|
238
|
+
} else if (routeIsChanging && dest.from) {
|
|
235
239
|
fromPath = dest.from;
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
240
|
+
if (process.env.NODE_ENV !== "production" && dest._isNavigate) {
|
|
241
|
+
const allFromMatches = this.getMatchedRoutes(
|
|
242
|
+
dest.from,
|
|
243
|
+
void 0
|
|
244
|
+
).matchedRoutes;
|
|
245
|
+
const matchedFrom = [...allCurrentLocationMatches].reverse().find((d) => {
|
|
246
|
+
return comparePaths(d.fullPath, fromPath);
|
|
247
|
+
});
|
|
248
|
+
const matchedCurrent = [...allFromMatches].reverse().find((d) => {
|
|
249
|
+
return comparePaths(d.fullPath, currentLocation.pathname);
|
|
250
|
+
});
|
|
251
|
+
if (!matchedFrom && !matchedCurrent) {
|
|
252
|
+
console.warn(`Could not find match for from: ${fromPath}`);
|
|
253
|
+
}
|
|
241
254
|
}
|
|
242
255
|
}
|
|
243
256
|
const fromSearch = lastMatch.search;
|
|
244
257
|
const fromParams = { ...lastMatch.params };
|
|
245
|
-
const nextTo = dest.to ? this.resolvePathWithBase(fromPath, `${dest.to}`) : fromPath;
|
|
246
|
-
let nextParams = (dest.params ?? true) === true ? fromParams : {
|
|
258
|
+
const nextTo = dest.to ? this.resolvePathWithBase(fromPath, `${dest.to}`) : this.resolvePathWithBase(fromPath, ".");
|
|
259
|
+
let nextParams = dest.params === false || dest.params === null ? {} : (dest.params ?? true) === true ? fromParams : {
|
|
247
260
|
...fromParams,
|
|
248
261
|
...functionalUpdate(dest.params, fromParams)
|
|
249
262
|
};
|
|
263
|
+
const interpolatedNextTo = interpolatePath({
|
|
264
|
+
path: nextTo,
|
|
265
|
+
params: nextParams ?? {},
|
|
266
|
+
parseCache: this.parsePathnameCache
|
|
267
|
+
}).interpolatedPath;
|
|
250
268
|
const destRoutes = this.matchRoutes(
|
|
251
|
-
|
|
269
|
+
interpolatedNextTo,
|
|
252
270
|
{},
|
|
253
271
|
{
|
|
254
272
|
_buildLocation: true
|
|
@@ -256,21 +274,23 @@ class RouterCore {
|
|
|
256
274
|
).map((d) => this.looseRoutesById[d.routeId]);
|
|
257
275
|
if (Object.keys(nextParams).length > 0) {
|
|
258
276
|
destRoutes.map((route) => {
|
|
259
|
-
|
|
260
|
-
return ((_a2 = route.options.params) == null ? void 0 : _a2.stringify) ?? route.options.stringifyParams;
|
|
277
|
+
return route.options.params?.stringify ?? route.options.stringifyParams;
|
|
261
278
|
}).filter(Boolean).forEach((fn) => {
|
|
262
279
|
nextParams = { ...nextParams, ...fn(nextParams) };
|
|
263
280
|
});
|
|
264
281
|
}
|
|
265
282
|
const nextPathname = interpolatePath({
|
|
283
|
+
// Use the original template path for interpolation
|
|
284
|
+
// This preserves the original parameter syntax including optional parameters
|
|
266
285
|
path: nextTo,
|
|
267
286
|
params: nextParams ?? {},
|
|
268
287
|
leaveWildcards: false,
|
|
269
288
|
leaveParams: opts.leaveParams,
|
|
270
|
-
decodeCharMap: this.pathParamsDecodeCharMap
|
|
289
|
+
decodeCharMap: this.pathParamsDecodeCharMap,
|
|
290
|
+
parseCache: this.parsePathnameCache
|
|
271
291
|
}).interpolatedPath;
|
|
272
292
|
let nextSearch = fromSearch;
|
|
273
|
-
if (opts._includeValidateSearch &&
|
|
293
|
+
if (opts._includeValidateSearch && this.options.search?.strict) {
|
|
274
294
|
let validatedSearch = {};
|
|
275
295
|
destRoutes.forEach((route) => {
|
|
276
296
|
try {
|
|
@@ -311,17 +331,21 @@ class RouterCore {
|
|
|
311
331
|
};
|
|
312
332
|
};
|
|
313
333
|
const buildWithMatches = (dest = {}, maskedDest) => {
|
|
314
|
-
var _a;
|
|
315
334
|
const next = build(dest);
|
|
316
335
|
let maskedNext = maskedDest ? build(maskedDest) : void 0;
|
|
317
336
|
if (!maskedNext) {
|
|
318
337
|
let params = {};
|
|
319
|
-
const foundMask =
|
|
320
|
-
const match = matchPathname(
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
338
|
+
const foundMask = this.options.routeMasks?.find((d) => {
|
|
339
|
+
const match = matchPathname(
|
|
340
|
+
this.basepath,
|
|
341
|
+
next.pathname,
|
|
342
|
+
{
|
|
343
|
+
to: d.from,
|
|
344
|
+
caseSensitive: false,
|
|
345
|
+
fuzzy: false
|
|
346
|
+
},
|
|
347
|
+
this.parsePathnameCache
|
|
348
|
+
);
|
|
325
349
|
if (match) {
|
|
326
350
|
params = match;
|
|
327
351
|
return true;
|
|
@@ -360,6 +384,8 @@ class RouterCore {
|
|
|
360
384
|
const isSameState = () => {
|
|
361
385
|
const ignoredProps = [
|
|
362
386
|
"key",
|
|
387
|
+
// TODO: Remove in v2 - use __TSR_key instead
|
|
388
|
+
"__TSR_key",
|
|
363
389
|
"__TSR_index",
|
|
364
390
|
"__hashScrollIntoViewOptions"
|
|
365
391
|
];
|
|
@@ -375,7 +401,7 @@ class RouterCore {
|
|
|
375
401
|
const isSameUrl = this.latestLocation.href === next.href;
|
|
376
402
|
const previousCommitPromise = this.commitLocationPromise;
|
|
377
403
|
this.commitLocationPromise = createControlledPromise(() => {
|
|
378
|
-
previousCommitPromise
|
|
404
|
+
previousCommitPromise?.resolve();
|
|
379
405
|
});
|
|
380
406
|
if (isSameUrl && isSameState()) {
|
|
381
407
|
this.load();
|
|
@@ -394,7 +420,9 @@ class RouterCore {
|
|
|
394
420
|
...nextHistory.state,
|
|
395
421
|
__tempKey: void 0,
|
|
396
422
|
__tempLocation: void 0,
|
|
423
|
+
__TSR_key: void 0,
|
|
397
424
|
key: void 0
|
|
425
|
+
// TODO: Remove in v2 - use __TSR_key instead
|
|
398
426
|
}
|
|
399
427
|
}
|
|
400
428
|
}
|
|
@@ -466,37 +494,58 @@ class RouterCore {
|
|
|
466
494
|
} else {
|
|
467
495
|
window.location.href = href;
|
|
468
496
|
}
|
|
469
|
-
return;
|
|
497
|
+
return Promise.resolve();
|
|
470
498
|
}
|
|
471
499
|
return this.buildAndCommitLocation({
|
|
472
500
|
...rest,
|
|
473
501
|
href,
|
|
474
|
-
to
|
|
502
|
+
to,
|
|
503
|
+
_isNavigate: true
|
|
475
504
|
});
|
|
476
505
|
};
|
|
477
506
|
this.beforeLoad = () => {
|
|
478
507
|
this.cancelMatches();
|
|
479
508
|
this.latestLocation = this.parseLocation(this.latestLocation);
|
|
509
|
+
if (this.isServer) {
|
|
510
|
+
const nextLocation = this.buildLocation({
|
|
511
|
+
to: this.latestLocation.pathname,
|
|
512
|
+
search: true,
|
|
513
|
+
params: true,
|
|
514
|
+
hash: true,
|
|
515
|
+
state: true,
|
|
516
|
+
_includeValidateSearch: true
|
|
517
|
+
});
|
|
518
|
+
const normalizeUrl = (url) => {
|
|
519
|
+
try {
|
|
520
|
+
return encodeURI(decodeURI(url));
|
|
521
|
+
} catch {
|
|
522
|
+
return url;
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
if (trimPath(normalizeUrl(this.latestLocation.href)) !== trimPath(normalizeUrl(nextLocation.href))) {
|
|
526
|
+
throw redirect({ href: nextLocation.href });
|
|
527
|
+
}
|
|
528
|
+
}
|
|
480
529
|
const pendingMatches = this.matchRoutes(this.latestLocation);
|
|
481
530
|
this.__store.setState((s) => ({
|
|
482
531
|
...s,
|
|
483
532
|
status: "pending",
|
|
533
|
+
statusCode: 200,
|
|
484
534
|
isLoading: true,
|
|
485
535
|
location: this.latestLocation,
|
|
486
536
|
pendingMatches,
|
|
487
537
|
// If a cached moved to pendingMatches, remove it from cachedMatches
|
|
488
|
-
cachedMatches: s.cachedMatches.filter(
|
|
489
|
-
|
|
490
|
-
|
|
538
|
+
cachedMatches: s.cachedMatches.filter(
|
|
539
|
+
(d) => !pendingMatches.some((e) => e.id === d.id)
|
|
540
|
+
)
|
|
491
541
|
}));
|
|
492
542
|
};
|
|
493
543
|
this.load = async (opts) => {
|
|
494
|
-
let
|
|
544
|
+
let redirect2;
|
|
495
545
|
let notFound;
|
|
496
546
|
let loadPromise;
|
|
497
547
|
loadPromise = new Promise((resolve) => {
|
|
498
548
|
this.startTransition(async () => {
|
|
499
|
-
var _a;
|
|
500
549
|
try {
|
|
501
550
|
this.beforeLoad();
|
|
502
551
|
const next = this.latestLocation;
|
|
@@ -518,7 +567,7 @@ class RouterCore {
|
|
|
518
567
|
})
|
|
519
568
|
});
|
|
520
569
|
await this.loadMatches({
|
|
521
|
-
sync: opts
|
|
570
|
+
sync: opts?.sync,
|
|
522
571
|
matches: this.state.pendingMatches,
|
|
523
572
|
location: next,
|
|
524
573
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
@@ -532,13 +581,13 @@ class RouterCore {
|
|
|
532
581
|
const previousMatches = s.matches;
|
|
533
582
|
const newMatches = s.pendingMatches || s.matches;
|
|
534
583
|
exitingMatches = previousMatches.filter(
|
|
535
|
-
(match) => !newMatches.
|
|
584
|
+
(match) => !newMatches.some((d) => d.id === match.id)
|
|
536
585
|
);
|
|
537
586
|
enteringMatches = newMatches.filter(
|
|
538
|
-
(match) => !previousMatches.
|
|
587
|
+
(match) => !previousMatches.some((d) => d.id === match.id)
|
|
539
588
|
);
|
|
540
589
|
stayingMatches = previousMatches.filter(
|
|
541
|
-
(match) => newMatches.
|
|
590
|
+
(match) => newMatches.some((d) => d.id === match.id)
|
|
542
591
|
);
|
|
543
592
|
return {
|
|
544
593
|
...s,
|
|
@@ -560,8 +609,7 @@ class RouterCore {
|
|
|
560
609
|
[stayingMatches, "onStay"]
|
|
561
610
|
].forEach(([matches, hook]) => {
|
|
562
611
|
matches.forEach((match) => {
|
|
563
|
-
|
|
564
|
-
(_b = (_a2 = this.looseRoutesById[match.routeId].options)[hook]) == null ? void 0 : _b.call(_a2, match);
|
|
612
|
+
this.looseRoutesById[match.routeId].options[hook]?.(match);
|
|
565
613
|
});
|
|
566
614
|
});
|
|
567
615
|
});
|
|
@@ -569,10 +617,10 @@ class RouterCore {
|
|
|
569
617
|
});
|
|
570
618
|
} catch (err) {
|
|
571
619
|
if (isRedirect(err)) {
|
|
572
|
-
|
|
620
|
+
redirect2 = err;
|
|
573
621
|
if (!this.isServer) {
|
|
574
622
|
this.navigate({
|
|
575
|
-
...
|
|
623
|
+
...redirect2.options,
|
|
576
624
|
replace: true,
|
|
577
625
|
ignoreBlocker: true
|
|
578
626
|
});
|
|
@@ -582,12 +630,12 @@ class RouterCore {
|
|
|
582
630
|
}
|
|
583
631
|
this.__store.setState((s) => ({
|
|
584
632
|
...s,
|
|
585
|
-
statusCode:
|
|
586
|
-
redirect
|
|
633
|
+
statusCode: redirect2 ? redirect2.status : notFound ? 404 : s.matches.some((d) => d.status === "error") ? 500 : 200,
|
|
634
|
+
redirect: redirect2
|
|
587
635
|
}));
|
|
588
636
|
}
|
|
589
637
|
if (this.latestLoadPromise === loadPromise) {
|
|
590
|
-
|
|
638
|
+
this.commitLocationPromise?.resolve();
|
|
591
639
|
this.latestLoadPromise = void 0;
|
|
592
640
|
this.commitLocationPromise = void 0;
|
|
593
641
|
}
|
|
@@ -633,31 +681,17 @@ class RouterCore {
|
|
|
633
681
|
}
|
|
634
682
|
};
|
|
635
683
|
this.updateMatch = (id, updater) => {
|
|
636
|
-
|
|
637
|
-
let updated;
|
|
638
|
-
const isPending = (_a = this.state.pendingMatches) == null ? void 0 : _a.find((d) => d.id === id);
|
|
639
|
-
const isMatched = this.state.matches.find((d) => d.id === id);
|
|
640
|
-
const isCached = this.state.cachedMatches.find((d) => d.id === id);
|
|
641
|
-
const matchesKey = isPending ? "pendingMatches" : isMatched ? "matches" : isCached ? "cachedMatches" : "";
|
|
684
|
+
const matchesKey = this.state.pendingMatches?.some((d) => d.id === id) ? "pendingMatches" : this.state.matches.some((d) => d.id === id) ? "matches" : this.state.cachedMatches.some((d) => d.id === id) ? "cachedMatches" : "";
|
|
642
685
|
if (matchesKey) {
|
|
643
|
-
this.__store.setState((s) => {
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
[matchesKey]: (_a2 = s[matchesKey]) == null ? void 0 : _a2.map(
|
|
648
|
-
(d) => d.id === id ? updated = updater(d) : d
|
|
649
|
-
)
|
|
650
|
-
};
|
|
651
|
-
});
|
|
686
|
+
this.__store.setState((s) => ({
|
|
687
|
+
...s,
|
|
688
|
+
[matchesKey]: s[matchesKey]?.map((d) => d.id === id ? updater(d) : d)
|
|
689
|
+
}));
|
|
652
690
|
}
|
|
653
|
-
return updated;
|
|
654
691
|
};
|
|
655
692
|
this.getMatch = (matchId) => {
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
...this.state.pendingMatches ?? [],
|
|
659
|
-
...this.state.matches
|
|
660
|
-
].find((d) => d.id === matchId);
|
|
693
|
+
const findFn = (d) => d.id === matchId;
|
|
694
|
+
return this.state.cachedMatches.find(findFn) ?? this.state.pendingMatches?.find(findFn) ?? this.state.matches.find(findFn);
|
|
661
695
|
};
|
|
662
696
|
this.loadMatches = async ({
|
|
663
697
|
location,
|
|
@@ -672,14 +706,16 @@ class RouterCore {
|
|
|
672
706
|
const triggerOnReady = async () => {
|
|
673
707
|
if (!rendered) {
|
|
674
708
|
rendered = true;
|
|
675
|
-
await
|
|
709
|
+
await onReady?.();
|
|
676
710
|
}
|
|
677
711
|
};
|
|
678
712
|
const resolvePreload = (matchId) => {
|
|
679
|
-
return !!(allPreload && !this.state.matches.
|
|
713
|
+
return !!(allPreload && !this.state.matches.some((d) => d.id === matchId));
|
|
680
714
|
};
|
|
715
|
+
if (!this.isServer && this.state.matches.some((d) => d._forcePending)) {
|
|
716
|
+
triggerOnReady();
|
|
717
|
+
}
|
|
681
718
|
const handleRedirectAndNotFound = (match, err) => {
|
|
682
|
-
var _a, _b, _c, _d;
|
|
683
719
|
if (isRedirect(err) || isNotFound(err)) {
|
|
684
720
|
if (isRedirect(err)) {
|
|
685
721
|
if (err.redirectHandled) {
|
|
@@ -688,6 +724,8 @@ class RouterCore {
|
|
|
688
724
|
}
|
|
689
725
|
}
|
|
690
726
|
}
|
|
727
|
+
match.beforeLoadPromise?.resolve();
|
|
728
|
+
match.loaderPromise?.resolve();
|
|
691
729
|
updateMatch(match.id, (prev) => ({
|
|
692
730
|
...prev,
|
|
693
731
|
status: isRedirect(err) ? "redirected" : isNotFound(err) ? "notFound" : "error",
|
|
@@ -699,9 +737,7 @@ class RouterCore {
|
|
|
699
737
|
if (!err.routeId) {
|
|
700
738
|
err.routeId = match.routeId;
|
|
701
739
|
}
|
|
702
|
-
|
|
703
|
-
(_b = match.loaderPromise) == null ? void 0 : _b.resolve();
|
|
704
|
-
(_c = match.loadPromise) == null ? void 0 : _c.resolve();
|
|
740
|
+
match.loadPromise?.resolve();
|
|
705
741
|
if (isRedirect(err)) {
|
|
706
742
|
rendered = true;
|
|
707
743
|
err.options._fromLocation = location;
|
|
@@ -712,22 +748,28 @@ class RouterCore {
|
|
|
712
748
|
this._handleNotFound(matches, err, {
|
|
713
749
|
updateMatch
|
|
714
750
|
});
|
|
715
|
-
(_d = this.serverSsr) == null ? void 0 : _d.onMatchSettled({
|
|
716
|
-
router: this,
|
|
717
|
-
match: this.getMatch(match.id)
|
|
718
|
-
});
|
|
719
751
|
throw err;
|
|
720
752
|
}
|
|
721
753
|
}
|
|
722
754
|
};
|
|
755
|
+
const shouldSkipLoader = (matchId) => {
|
|
756
|
+
const match = this.getMatch(matchId);
|
|
757
|
+
if (!this.isServer && match._dehydrated) {
|
|
758
|
+
return true;
|
|
759
|
+
}
|
|
760
|
+
if (this.isServer) {
|
|
761
|
+
if (match.ssr === false) {
|
|
762
|
+
return true;
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
return false;
|
|
766
|
+
};
|
|
723
767
|
try {
|
|
724
768
|
await new Promise((resolveAll, rejectAll) => {
|
|
725
769
|
;
|
|
726
770
|
(async () => {
|
|
727
|
-
var _a, _b, _c, _d;
|
|
728
771
|
try {
|
|
729
772
|
const handleSerialError = (index, err, routerCode) => {
|
|
730
|
-
var _a2, _b2;
|
|
731
773
|
const { id: matchId, routeId } = matches[index];
|
|
732
774
|
const route = this.looseRoutesById[routeId];
|
|
733
775
|
if (err instanceof Promise) {
|
|
@@ -737,15 +779,14 @@ class RouterCore {
|
|
|
737
779
|
firstBadMatchIndex = firstBadMatchIndex ?? index;
|
|
738
780
|
handleRedirectAndNotFound(this.getMatch(matchId), err);
|
|
739
781
|
try {
|
|
740
|
-
|
|
782
|
+
route.options.onError?.(err);
|
|
741
783
|
} catch (errorHandlerErr) {
|
|
742
784
|
err = errorHandlerErr;
|
|
743
785
|
handleRedirectAndNotFound(this.getMatch(matchId), err);
|
|
744
786
|
}
|
|
745
787
|
updateMatch(matchId, (prev) => {
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
(_b3 = prev.loadPromise) == null ? void 0 : _b3.resolve();
|
|
788
|
+
prev.beforeLoadPromise?.resolve();
|
|
789
|
+
prev.loadPromise?.resolve();
|
|
749
790
|
return {
|
|
750
791
|
...prev,
|
|
751
792
|
error: err,
|
|
@@ -759,26 +800,94 @@ class RouterCore {
|
|
|
759
800
|
};
|
|
760
801
|
for (const [index, { id: matchId, routeId }] of matches.entries()) {
|
|
761
802
|
const existingMatch = this.getMatch(matchId);
|
|
762
|
-
const parentMatchId =
|
|
803
|
+
const parentMatchId = matches[index - 1]?.id;
|
|
804
|
+
const parentMatch = parentMatchId ? this.getMatch(parentMatchId) : void 0;
|
|
763
805
|
const route = this.looseRoutesById[routeId];
|
|
764
806
|
const pendingMs = route.options.pendingMs ?? this.options.defaultPendingMs;
|
|
765
|
-
|
|
807
|
+
if (this.isServer) {
|
|
808
|
+
let ssr;
|
|
809
|
+
if (this.isShell()) {
|
|
810
|
+
ssr = matchId === rootRouteId;
|
|
811
|
+
} else {
|
|
812
|
+
const defaultSsr = this.options.defaultSsr ?? true;
|
|
813
|
+
if (parentMatch?.ssr === false) {
|
|
814
|
+
ssr = false;
|
|
815
|
+
} else {
|
|
816
|
+
let tempSsr;
|
|
817
|
+
if (route.options.ssr === void 0) {
|
|
818
|
+
tempSsr = defaultSsr;
|
|
819
|
+
} else if (typeof route.options.ssr === "function") {
|
|
820
|
+
let makeMaybe = function(value, error) {
|
|
821
|
+
if (error) {
|
|
822
|
+
return { status: "error", error };
|
|
823
|
+
}
|
|
824
|
+
return { status: "success", value };
|
|
825
|
+
};
|
|
826
|
+
const { search, params } = this.getMatch(matchId);
|
|
827
|
+
const ssrFnContext = {
|
|
828
|
+
search: makeMaybe(search, existingMatch.searchError),
|
|
829
|
+
params: makeMaybe(params, existingMatch.paramsError),
|
|
830
|
+
location,
|
|
831
|
+
matches: matches.map((match) => ({
|
|
832
|
+
index: match.index,
|
|
833
|
+
pathname: match.pathname,
|
|
834
|
+
fullPath: match.fullPath,
|
|
835
|
+
staticData: match.staticData,
|
|
836
|
+
id: match.id,
|
|
837
|
+
routeId: match.routeId,
|
|
838
|
+
search: makeMaybe(match.search, match.searchError),
|
|
839
|
+
params: makeMaybe(match.params, match.paramsError),
|
|
840
|
+
ssr: match.ssr
|
|
841
|
+
}))
|
|
842
|
+
};
|
|
843
|
+
tempSsr = await route.options.ssr(ssrFnContext) ?? defaultSsr;
|
|
844
|
+
} else {
|
|
845
|
+
tempSsr = route.options.ssr;
|
|
846
|
+
}
|
|
847
|
+
if (tempSsr === true && parentMatch?.ssr === "data-only") {
|
|
848
|
+
ssr = "data-only";
|
|
849
|
+
} else {
|
|
850
|
+
ssr = tempSsr;
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
updateMatch(matchId, (prev) => ({
|
|
855
|
+
...prev,
|
|
856
|
+
ssr
|
|
857
|
+
}));
|
|
858
|
+
}
|
|
859
|
+
if (shouldSkipLoader(matchId)) {
|
|
860
|
+
continue;
|
|
861
|
+
}
|
|
862
|
+
const shouldPending = !!(onReady && !this.isServer && !resolvePreload(matchId) && (route.options.loader || route.options.beforeLoad || routeNeedsPreload(route)) && typeof pendingMs === "number" && pendingMs !== Infinity && (route.options.pendingComponent ?? this.options?.defaultPendingComponent));
|
|
766
863
|
let executeBeforeLoad = true;
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
existingMatch.beforeLoadPromise || existingMatch.loaderPromise
|
|
771
|
-
) {
|
|
772
|
-
if (shouldPending) {
|
|
773
|
-
setTimeout(() => {
|
|
864
|
+
const setupPendingTimeout = () => {
|
|
865
|
+
if (shouldPending && this.getMatch(matchId).pendingTimeout === void 0) {
|
|
866
|
+
const pendingTimeout = setTimeout(() => {
|
|
774
867
|
try {
|
|
775
868
|
triggerOnReady();
|
|
776
869
|
} catch {
|
|
777
870
|
}
|
|
778
871
|
}, pendingMs);
|
|
872
|
+
updateMatch(matchId, (prev) => ({
|
|
873
|
+
...prev,
|
|
874
|
+
pendingTimeout
|
|
875
|
+
}));
|
|
779
876
|
}
|
|
877
|
+
};
|
|
878
|
+
if (
|
|
879
|
+
// If we are in the middle of a load, either of these will be present
|
|
880
|
+
// (not to be confused with `loadPromise`, which is always defined)
|
|
881
|
+
existingMatch.beforeLoadPromise || existingMatch.loaderPromise
|
|
882
|
+
) {
|
|
883
|
+
setupPendingTimeout();
|
|
780
884
|
await existingMatch.beforeLoadPromise;
|
|
781
|
-
|
|
885
|
+
const match = this.getMatch(matchId);
|
|
886
|
+
if (match.status === "error") {
|
|
887
|
+
executeBeforeLoad = true;
|
|
888
|
+
} else if (match.preload && (match.status === "redirected" || match.status === "notFound")) {
|
|
889
|
+
handleRedirectAndNotFound(match, match.error);
|
|
890
|
+
}
|
|
782
891
|
}
|
|
783
892
|
if (executeBeforeLoad) {
|
|
784
893
|
try {
|
|
@@ -787,21 +896,11 @@ class RouterCore {
|
|
|
787
896
|
return {
|
|
788
897
|
...prev,
|
|
789
898
|
loadPromise: createControlledPromise(() => {
|
|
790
|
-
prevLoadPromise
|
|
899
|
+
prevLoadPromise?.resolve();
|
|
791
900
|
}),
|
|
792
901
|
beforeLoadPromise: createControlledPromise()
|
|
793
902
|
};
|
|
794
903
|
});
|
|
795
|
-
const abortController = new AbortController();
|
|
796
|
-
let pendingTimeout;
|
|
797
|
-
if (shouldPending) {
|
|
798
|
-
pendingTimeout = setTimeout(() => {
|
|
799
|
-
try {
|
|
800
|
-
triggerOnReady();
|
|
801
|
-
} catch {
|
|
802
|
-
}
|
|
803
|
-
}, pendingMs);
|
|
804
|
-
}
|
|
805
904
|
const { paramsError, searchError } = this.getMatch(matchId);
|
|
806
905
|
if (paramsError) {
|
|
807
906
|
handleSerialError(index, paramsError, "PARSE_PARAMS");
|
|
@@ -809,15 +908,16 @@ class RouterCore {
|
|
|
809
908
|
if (searchError) {
|
|
810
909
|
handleSerialError(index, searchError, "VALIDATE_SEARCH");
|
|
811
910
|
}
|
|
812
|
-
|
|
911
|
+
setupPendingTimeout();
|
|
912
|
+
const abortController = new AbortController();
|
|
913
|
+
const parentMatchContext = parentMatch?.context ?? this.options.context ?? {};
|
|
813
914
|
updateMatch(matchId, (prev) => ({
|
|
814
915
|
...prev,
|
|
815
916
|
isFetching: "beforeLoad",
|
|
816
917
|
fetchCount: prev.fetchCount + 1,
|
|
817
918
|
abortController,
|
|
818
|
-
pendingTimeout,
|
|
819
919
|
context: {
|
|
820
|
-
...
|
|
920
|
+
...parentMatchContext,
|
|
821
921
|
...prev.__routeContext
|
|
822
922
|
}
|
|
823
923
|
}));
|
|
@@ -835,7 +935,7 @@ class RouterCore {
|
|
|
835
935
|
cause: preload ? "preload" : cause,
|
|
836
936
|
matches
|
|
837
937
|
};
|
|
838
|
-
const beforeLoadContext = await
|
|
938
|
+
const beforeLoadContext = await route.options.beforeLoad?.(beforeLoadFnContext);
|
|
839
939
|
if (isRedirect(beforeLoadContext) || isNotFound(beforeLoadContext)) {
|
|
840
940
|
handleSerialError(index, beforeLoadContext, "BEFORE_LOAD");
|
|
841
941
|
}
|
|
@@ -844,7 +944,7 @@ class RouterCore {
|
|
|
844
944
|
...prev,
|
|
845
945
|
__beforeLoadContext: beforeLoadContext,
|
|
846
946
|
context: {
|
|
847
|
-
...
|
|
947
|
+
...parentMatchContext,
|
|
848
948
|
...prev.__routeContext,
|
|
849
949
|
...beforeLoadContext
|
|
850
950
|
},
|
|
@@ -855,8 +955,7 @@ class RouterCore {
|
|
|
855
955
|
handleSerialError(index, err, "BEFORE_LOAD");
|
|
856
956
|
}
|
|
857
957
|
updateMatch(matchId, (prev) => {
|
|
858
|
-
|
|
859
|
-
(_a2 = prev.beforeLoadPromise) == null ? void 0 : _a2.resolve();
|
|
958
|
+
prev.beforeLoadPromise?.resolve();
|
|
860
959
|
return {
|
|
861
960
|
...prev,
|
|
862
961
|
beforeLoadPromise: void 0,
|
|
@@ -870,18 +969,63 @@ class RouterCore {
|
|
|
870
969
|
validResolvedMatches.forEach(({ id: matchId, routeId }, index) => {
|
|
871
970
|
matchPromises.push(
|
|
872
971
|
(async () => {
|
|
873
|
-
const { loaderPromise: prevLoaderPromise } = this.getMatch(matchId);
|
|
874
972
|
let loaderShouldRunAsync = false;
|
|
875
973
|
let loaderIsRunningAsync = false;
|
|
876
|
-
|
|
877
|
-
|
|
974
|
+
const route = this.looseRoutesById[routeId];
|
|
975
|
+
const executeHead = async () => {
|
|
976
|
+
const match = this.getMatch(matchId);
|
|
977
|
+
if (!match) {
|
|
978
|
+
return;
|
|
979
|
+
}
|
|
980
|
+
const assetContext = {
|
|
981
|
+
matches,
|
|
982
|
+
match,
|
|
983
|
+
params: match.params,
|
|
984
|
+
loaderData: match.loaderData
|
|
985
|
+
};
|
|
986
|
+
const headFnContent = await route.options.head?.(assetContext);
|
|
987
|
+
const meta = headFnContent?.meta;
|
|
988
|
+
const links = headFnContent?.links;
|
|
989
|
+
const headScripts = headFnContent?.scripts;
|
|
990
|
+
const styles = headFnContent?.styles;
|
|
991
|
+
const scripts = await route.options.scripts?.(assetContext);
|
|
992
|
+
const headers = await route.options.headers?.(assetContext);
|
|
993
|
+
return {
|
|
994
|
+
meta,
|
|
995
|
+
links,
|
|
996
|
+
headScripts,
|
|
997
|
+
headers,
|
|
998
|
+
scripts,
|
|
999
|
+
styles
|
|
1000
|
+
};
|
|
1001
|
+
};
|
|
1002
|
+
const potentialPendingMinPromise = async () => {
|
|
1003
|
+
const latestMatch = this.getMatch(matchId);
|
|
1004
|
+
if (latestMatch.minPendingPromise) {
|
|
1005
|
+
await latestMatch.minPendingPromise;
|
|
1006
|
+
}
|
|
1007
|
+
};
|
|
1008
|
+
const prevMatch = this.getMatch(matchId);
|
|
1009
|
+
if (shouldSkipLoader(matchId)) {
|
|
1010
|
+
if (this.isServer) {
|
|
1011
|
+
const head = await executeHead();
|
|
1012
|
+
updateMatch(matchId, (prev) => ({
|
|
1013
|
+
...prev,
|
|
1014
|
+
...head
|
|
1015
|
+
}));
|
|
1016
|
+
return this.getMatch(matchId);
|
|
1017
|
+
}
|
|
1018
|
+
} else if (prevMatch.loaderPromise) {
|
|
1019
|
+
if (prevMatch.status === "success" && !sync && !prevMatch.preload) {
|
|
1020
|
+
return this.getMatch(matchId);
|
|
1021
|
+
}
|
|
1022
|
+
await prevMatch.loaderPromise;
|
|
878
1023
|
const match = this.getMatch(matchId);
|
|
879
1024
|
if (match.error) {
|
|
880
1025
|
handleRedirectAndNotFound(match, match.error);
|
|
881
1026
|
}
|
|
882
1027
|
} else {
|
|
883
1028
|
const parentMatchPromise = matchPromises[index - 1];
|
|
884
|
-
const route = this.looseRoutesById[routeId];
|
|
885
1029
|
const getLoaderContext = () => {
|
|
886
1030
|
const {
|
|
887
1031
|
params,
|
|
@@ -912,49 +1056,29 @@ class RouterCore {
|
|
|
912
1056
|
updateMatch(matchId, (prev) => ({
|
|
913
1057
|
...prev,
|
|
914
1058
|
loaderPromise: createControlledPromise(),
|
|
915
|
-
preload: !!preload && !this.state.matches.
|
|
1059
|
+
preload: !!preload && !this.state.matches.some((d) => d.id === matchId)
|
|
916
1060
|
}));
|
|
917
|
-
const executeHead = async () => {
|
|
918
|
-
var _a2, _b2, _c2, _d2, _e, _f;
|
|
919
|
-
const match = this.getMatch(matchId);
|
|
920
|
-
if (!match) {
|
|
921
|
-
return;
|
|
922
|
-
}
|
|
923
|
-
const assetContext = {
|
|
924
|
-
matches,
|
|
925
|
-
match,
|
|
926
|
-
params: match.params,
|
|
927
|
-
loaderData: match.loaderData
|
|
928
|
-
};
|
|
929
|
-
const headFnContent = await ((_b2 = (_a2 = route.options).head) == null ? void 0 : _b2.call(_a2, assetContext));
|
|
930
|
-
const meta = headFnContent == null ? void 0 : headFnContent.meta;
|
|
931
|
-
const links = headFnContent == null ? void 0 : headFnContent.links;
|
|
932
|
-
const headScripts = headFnContent == null ? void 0 : headFnContent.scripts;
|
|
933
|
-
const scripts = await ((_d2 = (_c2 = route.options).scripts) == null ? void 0 : _d2.call(_c2, assetContext));
|
|
934
|
-
const headers = await ((_f = (_e = route.options).headers) == null ? void 0 : _f.call(_e, assetContext));
|
|
935
|
-
return { meta, links, headScripts, headers, scripts };
|
|
936
|
-
};
|
|
937
1061
|
const runLoader = async () => {
|
|
938
|
-
var _a2, _b2, _c2, _d2, _e;
|
|
939
1062
|
try {
|
|
940
|
-
const potentialPendingMinPromise = async () => {
|
|
941
|
-
const latestMatch = this.getMatch(matchId);
|
|
942
|
-
if (latestMatch.minPendingPromise) {
|
|
943
|
-
await latestMatch.minPendingPromise;
|
|
944
|
-
}
|
|
945
|
-
};
|
|
946
1063
|
try {
|
|
947
|
-
this.
|
|
1064
|
+
if (!this.isServer || this.isServer && this.getMatch(matchId).ssr === true) {
|
|
1065
|
+
this.loadRouteChunk(route);
|
|
1066
|
+
}
|
|
948
1067
|
updateMatch(matchId, (prev) => ({
|
|
949
1068
|
...prev,
|
|
950
1069
|
isFetching: "loader"
|
|
951
1070
|
}));
|
|
952
|
-
const loaderData = await
|
|
1071
|
+
const loaderData = await route.options.loader?.(getLoaderContext());
|
|
953
1072
|
handleRedirectAndNotFound(
|
|
954
1073
|
this.getMatch(matchId),
|
|
955
1074
|
loaderData
|
|
956
1075
|
);
|
|
1076
|
+
updateMatch(matchId, (prev) => ({
|
|
1077
|
+
...prev,
|
|
1078
|
+
loaderData
|
|
1079
|
+
}));
|
|
957
1080
|
await route._lazyPromise;
|
|
1081
|
+
const head = await executeHead();
|
|
958
1082
|
await potentialPendingMinPromise();
|
|
959
1083
|
await route._componentsPromise;
|
|
960
1084
|
updateMatch(matchId, (prev) => ({
|
|
@@ -963,11 +1087,6 @@ class RouterCore {
|
|
|
963
1087
|
status: "success",
|
|
964
1088
|
isFetching: false,
|
|
965
1089
|
updatedAt: Date.now(),
|
|
966
|
-
loaderData
|
|
967
|
-
}));
|
|
968
|
-
const head = await executeHead();
|
|
969
|
-
updateMatch(matchId, (prev) => ({
|
|
970
|
-
...prev,
|
|
971
1090
|
...head
|
|
972
1091
|
}));
|
|
973
1092
|
} catch (e) {
|
|
@@ -975,7 +1094,7 @@ class RouterCore {
|
|
|
975
1094
|
await potentialPendingMinPromise();
|
|
976
1095
|
handleRedirectAndNotFound(this.getMatch(matchId), e);
|
|
977
1096
|
try {
|
|
978
|
-
|
|
1097
|
+
route.options.onError?.(e);
|
|
979
1098
|
} catch (onErrorError) {
|
|
980
1099
|
error = onErrorError;
|
|
981
1100
|
handleRedirectAndNotFound(
|
|
@@ -992,10 +1111,6 @@ class RouterCore {
|
|
|
992
1111
|
...head
|
|
993
1112
|
}));
|
|
994
1113
|
}
|
|
995
|
-
(_e = this.serverSsr) == null ? void 0 : _e.onMatchSettled({
|
|
996
|
-
router: this,
|
|
997
|
-
match: this.getMatch(matchId)
|
|
998
|
-
});
|
|
999
1114
|
} catch (err) {
|
|
1000
1115
|
const head = await executeHead();
|
|
1001
1116
|
updateMatch(matchId, (prev) => ({
|
|
@@ -1015,8 +1130,8 @@ class RouterCore {
|
|
|
1015
1130
|
try {
|
|
1016
1131
|
await runLoader();
|
|
1017
1132
|
const { loaderPromise, loadPromise } = this.getMatch(matchId);
|
|
1018
|
-
loaderPromise
|
|
1019
|
-
loadPromise
|
|
1133
|
+
loaderPromise?.resolve();
|
|
1134
|
+
loadPromise?.resolve();
|
|
1020
1135
|
updateMatch(matchId, (prev) => ({
|
|
1021
1136
|
...prev,
|
|
1022
1137
|
loaderPromise: void 0
|
|
@@ -1039,15 +1154,20 @@ class RouterCore {
|
|
|
1039
1154
|
}
|
|
1040
1155
|
if (!loaderIsRunningAsync) {
|
|
1041
1156
|
const { loaderPromise, loadPromise } = this.getMatch(matchId);
|
|
1042
|
-
loaderPromise
|
|
1043
|
-
loadPromise
|
|
1157
|
+
loaderPromise?.resolve();
|
|
1158
|
+
loadPromise?.resolve();
|
|
1044
1159
|
}
|
|
1045
|
-
updateMatch(matchId, (prev) =>
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1160
|
+
updateMatch(matchId, (prev) => {
|
|
1161
|
+
clearTimeout(prev.pendingTimeout);
|
|
1162
|
+
return {
|
|
1163
|
+
...prev,
|
|
1164
|
+
isFetching: loaderIsRunningAsync ? prev.isFetching : false,
|
|
1165
|
+
loaderPromise: loaderIsRunningAsync ? prev.loaderPromise : void 0,
|
|
1166
|
+
invalid: false,
|
|
1167
|
+
pendingTimeout: void 0,
|
|
1168
|
+
_dehydrated: void 0
|
|
1169
|
+
};
|
|
1170
|
+
});
|
|
1051
1171
|
return this.getMatch(matchId);
|
|
1052
1172
|
})()
|
|
1053
1173
|
);
|
|
@@ -1072,40 +1192,36 @@ class RouterCore {
|
|
|
1072
1192
|
};
|
|
1073
1193
|
this.invalidate = (opts) => {
|
|
1074
1194
|
const invalidate = (d) => {
|
|
1075
|
-
|
|
1076
|
-
if (((_a = opts == null ? void 0 : opts.filter) == null ? void 0 : _a.call(opts, d)) ?? true) {
|
|
1195
|
+
if (opts?.filter?.(d) ?? true) {
|
|
1077
1196
|
return {
|
|
1078
1197
|
...d,
|
|
1079
1198
|
invalid: true,
|
|
1080
|
-
...d.status === "error" ? { status: "pending", error: void 0 } : {}
|
|
1199
|
+
...opts?.forcePending || d.status === "error" ? { status: "pending", error: void 0 } : {}
|
|
1081
1200
|
};
|
|
1082
1201
|
}
|
|
1083
1202
|
return d;
|
|
1084
1203
|
};
|
|
1085
|
-
this.__store.setState((s) => {
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
pendingMatches: (_a = s.pendingMatches) == null ? void 0 : _a.map(invalidate)
|
|
1092
|
-
};
|
|
1093
|
-
});
|
|
1204
|
+
this.__store.setState((s) => ({
|
|
1205
|
+
...s,
|
|
1206
|
+
matches: s.matches.map(invalidate),
|
|
1207
|
+
cachedMatches: s.cachedMatches.map(invalidate),
|
|
1208
|
+
pendingMatches: s.pendingMatches?.map(invalidate)
|
|
1209
|
+
}));
|
|
1094
1210
|
this.shouldViewTransition = false;
|
|
1095
|
-
return this.load({ sync: opts
|
|
1211
|
+
return this.load({ sync: opts?.sync });
|
|
1096
1212
|
};
|
|
1097
|
-
this.resolveRedirect = (
|
|
1098
|
-
if (!
|
|
1099
|
-
|
|
1100
|
-
|
|
1213
|
+
this.resolveRedirect = (redirect2) => {
|
|
1214
|
+
if (!redirect2.options.href) {
|
|
1215
|
+
redirect2.options.href = this.buildLocation(redirect2.options).href;
|
|
1216
|
+
redirect2.headers.set("Location", redirect2.options.href);
|
|
1101
1217
|
}
|
|
1102
|
-
if (!
|
|
1103
|
-
|
|
1218
|
+
if (!redirect2.headers.get("Location")) {
|
|
1219
|
+
redirect2.headers.set("Location", redirect2.options.href);
|
|
1104
1220
|
}
|
|
1105
|
-
return
|
|
1221
|
+
return redirect2;
|
|
1106
1222
|
};
|
|
1107
1223
|
this.clearCache = (opts) => {
|
|
1108
|
-
const filter = opts
|
|
1224
|
+
const filter = opts?.filter;
|
|
1109
1225
|
if (filter !== void 0) {
|
|
1110
1226
|
this.__store.setState((s) => {
|
|
1111
1227
|
return {
|
|
@@ -1131,7 +1247,10 @@ class RouterCore {
|
|
|
1131
1247
|
return true;
|
|
1132
1248
|
}
|
|
1133
1249
|
const gcTime = (d.preload ? route.options.preloadGcTime ?? this.options.defaultPreloadGcTime : route.options.gcTime ?? this.options.defaultGcTime) ?? 5 * 60 * 1e3;
|
|
1134
|
-
|
|
1250
|
+
const isError = d.status === "error";
|
|
1251
|
+
if (isError) return true;
|
|
1252
|
+
const gcEligible = Date.now() - d.updatedAt >= gcTime;
|
|
1253
|
+
return gcEligible;
|
|
1135
1254
|
};
|
|
1136
1255
|
this.clearCache({ filter });
|
|
1137
1256
|
};
|
|
@@ -1151,7 +1270,7 @@ class RouterCore {
|
|
|
1151
1270
|
() => Promise.all(
|
|
1152
1271
|
componentTypes.map(async (type) => {
|
|
1153
1272
|
const component = route.options[type];
|
|
1154
|
-
if (component
|
|
1273
|
+
if (component?.preload) {
|
|
1155
1274
|
await component.preload();
|
|
1156
1275
|
}
|
|
1157
1276
|
})
|
|
@@ -1227,15 +1346,20 @@ class RouterCore {
|
|
|
1227
1346
|
leaveParams: true
|
|
1228
1347
|
};
|
|
1229
1348
|
const next = this.buildLocation(matchLocation);
|
|
1230
|
-
if (
|
|
1349
|
+
if (opts?.pending && this.state.status !== "pending") {
|
|
1231
1350
|
return false;
|
|
1232
1351
|
}
|
|
1233
|
-
const pending =
|
|
1352
|
+
const pending = opts?.pending === void 0 ? !this.state.isLoading : opts.pending;
|
|
1234
1353
|
const baseLocation = pending ? this.latestLocation : this.state.resolvedLocation || this.state.location;
|
|
1235
|
-
const match = matchPathname(
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1354
|
+
const match = matchPathname(
|
|
1355
|
+
this.basepath,
|
|
1356
|
+
baseLocation.pathname,
|
|
1357
|
+
{
|
|
1358
|
+
...opts,
|
|
1359
|
+
to: next.pathname
|
|
1360
|
+
},
|
|
1361
|
+
this.parsePathnameCache
|
|
1362
|
+
);
|
|
1239
1363
|
if (!match) {
|
|
1240
1364
|
return false;
|
|
1241
1365
|
}
|
|
@@ -1244,7 +1368,7 @@ class RouterCore {
|
|
|
1244
1368
|
return false;
|
|
1245
1369
|
}
|
|
1246
1370
|
}
|
|
1247
|
-
if (match && (
|
|
1371
|
+
if (match && (opts?.includeSearch ?? true)) {
|
|
1248
1372
|
return deepEqual(baseLocation.search, next.search, { partial: true }) ? match : false;
|
|
1249
1373
|
}
|
|
1250
1374
|
return match;
|
|
@@ -1252,13 +1376,12 @@ class RouterCore {
|
|
|
1252
1376
|
this._handleNotFound = (matches, err, {
|
|
1253
1377
|
updateMatch = this.updateMatch
|
|
1254
1378
|
} = {}) => {
|
|
1255
|
-
var _a;
|
|
1256
1379
|
const routeCursor = this.routesById[err.routeId ?? ""] ?? this.routeTree;
|
|
1257
1380
|
const matchesByRouteId = {};
|
|
1258
1381
|
for (const match of matches) {
|
|
1259
1382
|
matchesByRouteId[match.routeId] = match;
|
|
1260
1383
|
}
|
|
1261
|
-
if (!routeCursor.options.notFoundComponent &&
|
|
1384
|
+
if (!routeCursor.options.notFoundComponent && this.options?.defaultNotFoundComponent) {
|
|
1262
1385
|
routeCursor.options.notFoundComponent = this.options.defaultNotFoundComponent;
|
|
1263
1386
|
}
|
|
1264
1387
|
invariant(
|
|
@@ -1300,9 +1423,15 @@ class RouterCore {
|
|
|
1300
1423
|
parseSearch: options.parseSearch ?? defaultParseSearch
|
|
1301
1424
|
});
|
|
1302
1425
|
if (typeof document !== "undefined") {
|
|
1303
|
-
|
|
1426
|
+
self.__TSR_ROUTER__ = this;
|
|
1304
1427
|
}
|
|
1305
1428
|
}
|
|
1429
|
+
isShell() {
|
|
1430
|
+
return !!this.options.isShell;
|
|
1431
|
+
}
|
|
1432
|
+
isPrerendering() {
|
|
1433
|
+
return !!this.options.isPrerendering;
|
|
1434
|
+
}
|
|
1306
1435
|
get state() {
|
|
1307
1436
|
return this.__store.state;
|
|
1308
1437
|
}
|
|
@@ -1310,10 +1439,9 @@ class RouterCore {
|
|
|
1310
1439
|
return this.routesById;
|
|
1311
1440
|
}
|
|
1312
1441
|
matchRoutesInternal(next, opts) {
|
|
1313
|
-
var _a;
|
|
1314
1442
|
const { foundRoute, matchedRoutes, routeParams } = this.getMatchedRoutes(
|
|
1315
1443
|
next.pathname,
|
|
1316
|
-
|
|
1444
|
+
opts?.dest?.to
|
|
1317
1445
|
);
|
|
1318
1446
|
let isGlobalNotFound = false;
|
|
1319
1447
|
if (
|
|
@@ -1344,9 +1472,8 @@ class RouterCore {
|
|
|
1344
1472
|
return rootRouteId;
|
|
1345
1473
|
})();
|
|
1346
1474
|
const parseErrors = matchedRoutes.map((route) => {
|
|
1347
|
-
var _a2;
|
|
1348
1475
|
let parsedParamsError;
|
|
1349
|
-
const parseParams =
|
|
1476
|
+
const parseParams = route.options.params?.parse ?? route.options.parseParams;
|
|
1350
1477
|
if (parseParams) {
|
|
1351
1478
|
try {
|
|
1352
1479
|
const parsedParams = parseParams(routeParams);
|
|
@@ -1355,7 +1482,7 @@ class RouterCore {
|
|
|
1355
1482
|
parsedParamsError = new PathParamError(err.message, {
|
|
1356
1483
|
cause: err
|
|
1357
1484
|
});
|
|
1358
|
-
if (opts
|
|
1485
|
+
if (opts?.throwOnError) {
|
|
1359
1486
|
throw parsedParamsError;
|
|
1360
1487
|
}
|
|
1361
1488
|
return parsedParamsError;
|
|
@@ -1365,16 +1492,15 @@ class RouterCore {
|
|
|
1365
1492
|
});
|
|
1366
1493
|
const matches = [];
|
|
1367
1494
|
const getParentContext = (parentMatch) => {
|
|
1368
|
-
const parentMatchId = parentMatch
|
|
1495
|
+
const parentMatchId = parentMatch?.id;
|
|
1369
1496
|
const parentContext = !parentMatchId ? this.options.context ?? {} : parentMatch.context ?? this.options.context ?? {};
|
|
1370
1497
|
return parentContext;
|
|
1371
1498
|
};
|
|
1372
1499
|
matchedRoutes.forEach((route, index) => {
|
|
1373
|
-
var _a2, _b;
|
|
1374
1500
|
const parentMatch = matches[index - 1];
|
|
1375
1501
|
const [preMatchSearch, strictMatchSearch, searchError] = (() => {
|
|
1376
|
-
const parentSearch =
|
|
1377
|
-
const parentStrictSearch =
|
|
1502
|
+
const parentSearch = parentMatch?.search ?? next.search;
|
|
1503
|
+
const parentStrictSearch = parentMatch?._strictSearch ?? {};
|
|
1378
1504
|
try {
|
|
1379
1505
|
const strictSearch = validateSearch(route.options.validateSearch, { ...parentSearch }) ?? {};
|
|
1380
1506
|
return [
|
|
@@ -1392,15 +1518,15 @@ class RouterCore {
|
|
|
1392
1518
|
cause: err
|
|
1393
1519
|
});
|
|
1394
1520
|
}
|
|
1395
|
-
if (opts
|
|
1521
|
+
if (opts?.throwOnError) {
|
|
1396
1522
|
throw searchParamError;
|
|
1397
1523
|
}
|
|
1398
1524
|
return [parentSearch, {}, searchParamError];
|
|
1399
1525
|
}
|
|
1400
1526
|
})();
|
|
1401
|
-
const loaderDeps =
|
|
1527
|
+
const loaderDeps = route.options.loaderDeps?.({
|
|
1402
1528
|
search: preMatchSearch
|
|
1403
|
-
})
|
|
1529
|
+
}) ?? "";
|
|
1404
1530
|
const loaderDepsHash = loaderDeps ? JSON.stringify(loaderDeps) : "";
|
|
1405
1531
|
const { usedParams, interpolatedPath } = interpolatePath({
|
|
1406
1532
|
path: route.fullPath,
|
|
@@ -1411,7 +1537,8 @@ class RouterCore {
|
|
|
1411
1537
|
path: route.id,
|
|
1412
1538
|
params: routeParams,
|
|
1413
1539
|
leaveWildcards: true,
|
|
1414
|
-
decodeCharMap: this.pathParamsDecodeCharMap
|
|
1540
|
+
decodeCharMap: this.pathParamsDecodeCharMap,
|
|
1541
|
+
parseCache: this.parsePathnameCache
|
|
1415
1542
|
}).interpolatedPath + loaderDepsHash;
|
|
1416
1543
|
const existingMatch = this.getMatch(matchId);
|
|
1417
1544
|
const previousMatch = this.state.matches.find(
|
|
@@ -1446,7 +1573,7 @@ class RouterCore {
|
|
|
1446
1573
|
error: void 0,
|
|
1447
1574
|
paramsError: parseErrors[index],
|
|
1448
1575
|
__routeContext: {},
|
|
1449
|
-
__beforeLoadContext:
|
|
1576
|
+
__beforeLoadContext: void 0,
|
|
1450
1577
|
context: {},
|
|
1451
1578
|
abortController: new AbortController(),
|
|
1452
1579
|
fetchCount: 0,
|
|
@@ -1463,7 +1590,7 @@ class RouterCore {
|
|
|
1463
1590
|
fullPath: route.fullPath
|
|
1464
1591
|
};
|
|
1465
1592
|
}
|
|
1466
|
-
if (!
|
|
1593
|
+
if (!opts?.preload) {
|
|
1467
1594
|
match.globalNotFound = globalNotFoundRouteId === route.id;
|
|
1468
1595
|
}
|
|
1469
1596
|
match.searchError = searchError;
|
|
@@ -1476,10 +1603,9 @@ class RouterCore {
|
|
|
1476
1603
|
matches.push(match);
|
|
1477
1604
|
});
|
|
1478
1605
|
matches.forEach((match, index) => {
|
|
1479
|
-
var _a2, _b;
|
|
1480
1606
|
const route = this.looseRoutesById[match.routeId];
|
|
1481
1607
|
const existingMatch = this.getMatch(match.id);
|
|
1482
|
-
if (!existingMatch &&
|
|
1608
|
+
if (!existingMatch && opts?._buildLocation !== true) {
|
|
1483
1609
|
const parentMatch = matches[index - 1];
|
|
1484
1610
|
const parentContext = getParentContext(parentMatch);
|
|
1485
1611
|
const contextFnContext = {
|
|
@@ -1494,7 +1620,7 @@ class RouterCore {
|
|
|
1494
1620
|
preload: !!match.preload,
|
|
1495
1621
|
matches
|
|
1496
1622
|
};
|
|
1497
|
-
match.__routeContext =
|
|
1623
|
+
match.__routeContext = route.options.context?.(contextFnContext) ?? {};
|
|
1498
1624
|
match.context = {
|
|
1499
1625
|
...parentContext,
|
|
1500
1626
|
...match.__routeContext,
|
|
@@ -1509,6 +1635,10 @@ class SearchParamError extends Error {
|
|
|
1509
1635
|
}
|
|
1510
1636
|
class PathParamError extends Error {
|
|
1511
1637
|
}
|
|
1638
|
+
const normalize = (str) => str.endsWith("/") && str.length > 1 ? str.slice(0, -1) : str;
|
|
1639
|
+
function comparePaths(a, b) {
|
|
1640
|
+
return normalize(a) === normalize(b);
|
|
1641
|
+
}
|
|
1512
1642
|
function lazyFn(fn, key) {
|
|
1513
1643
|
return async (...args) => {
|
|
1514
1644
|
const imported = await fn();
|
|
@@ -1556,14 +1686,33 @@ const componentTypes = [
|
|
|
1556
1686
|
"notFoundComponent"
|
|
1557
1687
|
];
|
|
1558
1688
|
function routeNeedsPreload(route) {
|
|
1559
|
-
var _a;
|
|
1560
1689
|
for (const componentType of componentTypes) {
|
|
1561
|
-
if (
|
|
1690
|
+
if (route.options[componentType]?.preload) {
|
|
1562
1691
|
return true;
|
|
1563
1692
|
}
|
|
1564
1693
|
}
|
|
1565
1694
|
return false;
|
|
1566
1695
|
}
|
|
1696
|
+
const REQUIRED_PARAM_BASE_SCORE = 0.5;
|
|
1697
|
+
const OPTIONAL_PARAM_BASE_SCORE = 0.4;
|
|
1698
|
+
const WILDCARD_PARAM_BASE_SCORE = 0.25;
|
|
1699
|
+
const BOTH_PRESENCE_BASE_SCORE = 0.05;
|
|
1700
|
+
const PREFIX_PRESENCE_BASE_SCORE = 0.02;
|
|
1701
|
+
const SUFFIX_PRESENCE_BASE_SCORE = 0.01;
|
|
1702
|
+
const PREFIX_LENGTH_SCORE_MULTIPLIER = 2e-4;
|
|
1703
|
+
const SUFFIX_LENGTH_SCORE_MULTIPLIER = 1e-4;
|
|
1704
|
+
function handleParam(segment, baseScore) {
|
|
1705
|
+
if (segment.prefixSegment && segment.suffixSegment) {
|
|
1706
|
+
return baseScore + BOTH_PRESENCE_BASE_SCORE + PREFIX_LENGTH_SCORE_MULTIPLIER * segment.prefixSegment.length + SUFFIX_LENGTH_SCORE_MULTIPLIER * segment.suffixSegment.length;
|
|
1707
|
+
}
|
|
1708
|
+
if (segment.prefixSegment) {
|
|
1709
|
+
return baseScore + PREFIX_PRESENCE_BASE_SCORE + PREFIX_LENGTH_SCORE_MULTIPLIER * segment.prefixSegment.length;
|
|
1710
|
+
}
|
|
1711
|
+
if (segment.suffixSegment) {
|
|
1712
|
+
return baseScore + SUFFIX_PRESENCE_BASE_SCORE + SUFFIX_LENGTH_SCORE_MULTIPLIER * segment.suffixSegment.length;
|
|
1713
|
+
}
|
|
1714
|
+
return baseScore;
|
|
1715
|
+
}
|
|
1567
1716
|
function processRouteTree({
|
|
1568
1717
|
routeTree,
|
|
1569
1718
|
initRoute
|
|
@@ -1572,7 +1721,7 @@ function processRouteTree({
|
|
|
1572
1721
|
const routesByPath = {};
|
|
1573
1722
|
const recurseRoutes = (childRoutes) => {
|
|
1574
1723
|
childRoutes.forEach((childRoute, i) => {
|
|
1575
|
-
initRoute
|
|
1724
|
+
initRoute?.(childRoute, i);
|
|
1576
1725
|
const existingRoute = routesById[childRoute.id];
|
|
1577
1726
|
invariant(
|
|
1578
1727
|
!existingRoute,
|
|
@@ -1586,7 +1735,7 @@ function processRouteTree({
|
|
|
1586
1735
|
}
|
|
1587
1736
|
}
|
|
1588
1737
|
const children = childRoute.children;
|
|
1589
|
-
if (children
|
|
1738
|
+
if (children?.length) {
|
|
1590
1739
|
recurseRoutes(children);
|
|
1591
1740
|
}
|
|
1592
1741
|
});
|
|
@@ -1595,46 +1744,52 @@ function processRouteTree({
|
|
|
1595
1744
|
const scoredRoutes = [];
|
|
1596
1745
|
const routes = Object.values(routesById);
|
|
1597
1746
|
routes.forEach((d, i) => {
|
|
1598
|
-
var _a;
|
|
1599
1747
|
if (d.isRoot || !d.path) {
|
|
1600
1748
|
return;
|
|
1601
1749
|
}
|
|
1602
1750
|
const trimmed = trimPathLeft(d.fullPath);
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1751
|
+
let parsed = parsePathname(trimmed);
|
|
1752
|
+
let skip = 0;
|
|
1753
|
+
while (parsed.length > skip + 1 && parsed[skip]?.value === "/") {
|
|
1754
|
+
skip++;
|
|
1606
1755
|
}
|
|
1607
|
-
|
|
1756
|
+
if (skip > 0) parsed = parsed.slice(skip);
|
|
1757
|
+
let optionalParamCount = 0;
|
|
1758
|
+
let hasStaticAfter = false;
|
|
1759
|
+
const scores = parsed.map((segment, index) => {
|
|
1608
1760
|
if (segment.value === "/") {
|
|
1609
1761
|
return 0.75;
|
|
1610
1762
|
}
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
if (segment.type ===
|
|
1615
|
-
|
|
1763
|
+
let baseScore = void 0;
|
|
1764
|
+
if (segment.type === SEGMENT_TYPE_PARAM) {
|
|
1765
|
+
baseScore = REQUIRED_PARAM_BASE_SCORE;
|
|
1766
|
+
} else if (segment.type === SEGMENT_TYPE_OPTIONAL_PARAM) {
|
|
1767
|
+
baseScore = OPTIONAL_PARAM_BASE_SCORE;
|
|
1768
|
+
optionalParamCount++;
|
|
1769
|
+
} else if (segment.type === SEGMENT_TYPE_WILDCARD) {
|
|
1770
|
+
baseScore = WILDCARD_PARAM_BASE_SCORE;
|
|
1616
1771
|
}
|
|
1617
|
-
if (
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
if (segment.type === "wildcard" && segment.prefixSegment) {
|
|
1627
|
-
return 0.27;
|
|
1628
|
-
}
|
|
1629
|
-
if (segment.type === "wildcard" && segment.suffixSegment) {
|
|
1630
|
-
return 0.26;
|
|
1631
|
-
}
|
|
1632
|
-
if (segment.type === "wildcard") {
|
|
1633
|
-
return 0.25;
|
|
1772
|
+
if (baseScore) {
|
|
1773
|
+
for (let i2 = index + 1; i2 < parsed.length; i2++) {
|
|
1774
|
+
const nextSegment = parsed[i2];
|
|
1775
|
+
if (nextSegment.type === SEGMENT_TYPE_PATHNAME && nextSegment.value !== "/") {
|
|
1776
|
+
hasStaticAfter = true;
|
|
1777
|
+
return handleParam(segment, baseScore + 0.2);
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1780
|
+
return handleParam(segment, baseScore);
|
|
1634
1781
|
}
|
|
1635
1782
|
return 1;
|
|
1636
1783
|
});
|
|
1637
|
-
scoredRoutes.push({
|
|
1784
|
+
scoredRoutes.push({
|
|
1785
|
+
child: d,
|
|
1786
|
+
trimmed,
|
|
1787
|
+
parsed,
|
|
1788
|
+
index: i,
|
|
1789
|
+
scores,
|
|
1790
|
+
optionalParamCount,
|
|
1791
|
+
hasStaticAfter
|
|
1792
|
+
});
|
|
1638
1793
|
});
|
|
1639
1794
|
const flatRoutes = scoredRoutes.sort((a, b) => {
|
|
1640
1795
|
const minLength = Math.min(a.scores.length, b.scores.length);
|
|
@@ -1644,6 +1799,15 @@ function processRouteTree({
|
|
|
1644
1799
|
}
|
|
1645
1800
|
}
|
|
1646
1801
|
if (a.scores.length !== b.scores.length) {
|
|
1802
|
+
if (a.optionalParamCount !== b.optionalParamCount) {
|
|
1803
|
+
if (a.hasStaticAfter === b.hasStaticAfter) {
|
|
1804
|
+
return a.optionalParamCount - b.optionalParamCount;
|
|
1805
|
+
} else if (a.hasStaticAfter && !b.hasStaticAfter) {
|
|
1806
|
+
return -1;
|
|
1807
|
+
} else if (!a.hasStaticAfter && b.hasStaticAfter) {
|
|
1808
|
+
return 1;
|
|
1809
|
+
}
|
|
1810
|
+
}
|
|
1647
1811
|
return b.scores.length - a.scores.length;
|
|
1648
1812
|
}
|
|
1649
1813
|
for (let i = 0; i < minLength; i++) {
|
|
@@ -1665,38 +1829,56 @@ function getMatchedRoutes({
|
|
|
1665
1829
|
caseSensitive,
|
|
1666
1830
|
routesByPath,
|
|
1667
1831
|
routesById,
|
|
1668
|
-
flatRoutes
|
|
1832
|
+
flatRoutes,
|
|
1833
|
+
parseCache
|
|
1669
1834
|
}) {
|
|
1670
1835
|
let routeParams = {};
|
|
1671
1836
|
const trimmedPath = trimPathRight(pathname);
|
|
1672
1837
|
const getMatchedParams = (route) => {
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1838
|
+
const result = matchPathname(
|
|
1839
|
+
basepath,
|
|
1840
|
+
trimmedPath,
|
|
1841
|
+
{
|
|
1842
|
+
to: route.fullPath,
|
|
1843
|
+
caseSensitive: route.options?.caseSensitive ?? caseSensitive,
|
|
1844
|
+
// we need fuzzy matching for `notFoundMode: 'fuzzy'`
|
|
1845
|
+
fuzzy: true
|
|
1846
|
+
},
|
|
1847
|
+
parseCache
|
|
1848
|
+
);
|
|
1679
1849
|
return result;
|
|
1680
1850
|
};
|
|
1681
1851
|
let foundRoute = routePathname !== void 0 ? routesByPath[routePathname] : void 0;
|
|
1682
1852
|
if (foundRoute) {
|
|
1683
1853
|
routeParams = getMatchedParams(foundRoute);
|
|
1684
1854
|
} else {
|
|
1685
|
-
|
|
1855
|
+
let fuzzyMatch = void 0;
|
|
1856
|
+
for (const route of flatRoutes) {
|
|
1686
1857
|
const matchedParams = getMatchedParams(route);
|
|
1687
1858
|
if (matchedParams) {
|
|
1688
|
-
|
|
1689
|
-
|
|
1859
|
+
if (route.path !== "/" && matchedParams["**"]) {
|
|
1860
|
+
if (!fuzzyMatch) {
|
|
1861
|
+
fuzzyMatch = { foundRoute: route, routeParams: matchedParams };
|
|
1862
|
+
}
|
|
1863
|
+
} else {
|
|
1864
|
+
foundRoute = route;
|
|
1865
|
+
routeParams = matchedParams;
|
|
1866
|
+
break;
|
|
1867
|
+
}
|
|
1690
1868
|
}
|
|
1691
|
-
|
|
1692
|
-
|
|
1869
|
+
}
|
|
1870
|
+
if (!foundRoute && fuzzyMatch) {
|
|
1871
|
+
foundRoute = fuzzyMatch.foundRoute;
|
|
1872
|
+
routeParams = fuzzyMatch.routeParams;
|
|
1873
|
+
}
|
|
1693
1874
|
}
|
|
1694
1875
|
let routeCursor = foundRoute || routesById[rootRouteId];
|
|
1695
1876
|
const matchedRoutes = [routeCursor];
|
|
1696
1877
|
while (routeCursor.parentRoute) {
|
|
1697
1878
|
routeCursor = routeCursor.parentRoute;
|
|
1698
|
-
matchedRoutes.
|
|
1879
|
+
matchedRoutes.push(routeCursor);
|
|
1699
1880
|
}
|
|
1881
|
+
matchedRoutes.reverse();
|
|
1700
1882
|
return { matchedRoutes, routeParams, foundRoute };
|
|
1701
1883
|
}
|
|
1702
1884
|
function applySearchMiddleware({
|
|
@@ -1707,10 +1889,9 @@ function applySearchMiddleware({
|
|
|
1707
1889
|
}) {
|
|
1708
1890
|
const allMiddlewares = destRoutes.reduce(
|
|
1709
1891
|
(acc, route) => {
|
|
1710
|
-
var _a;
|
|
1711
1892
|
const middlewares = [];
|
|
1712
1893
|
if ("search" in route.options) {
|
|
1713
|
-
if (
|
|
1894
|
+
if (route.options.search?.middlewares) {
|
|
1714
1895
|
middlewares.push(...route.options.search.middlewares);
|
|
1715
1896
|
}
|
|
1716
1897
|
} else if (route.options.preSearchFilters || route.options.postSearchFilters) {
|