@tanstack/router-core 1.155.0 → 1.157.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/dist/cjs/index.cjs +5 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +1 -0
- package/dist/cjs/isServer.d.cts +24 -0
- package/dist/cjs/load-matches.cjs +8 -7
- package/dist/cjs/load-matches.cjs.map +1 -1
- package/dist/cjs/new-process-route-tree.cjs.map +1 -1
- package/dist/cjs/new-process-route-tree.d.cts +13 -8
- package/dist/cjs/router.cjs +122 -54
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/router.d.cts +18 -4
- package/dist/cjs/scroll-restoration.cjs +3 -2
- package/dist/cjs/scroll-restoration.cjs.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/isServer.d.ts +24 -0
- package/dist/esm/load-matches.js +8 -7
- package/dist/esm/load-matches.js.map +1 -1
- package/dist/esm/new-process-route-tree.d.ts +13 -8
- package/dist/esm/new-process-route-tree.js.map +1 -1
- package/dist/esm/router.d.ts +18 -4
- package/dist/esm/router.js +123 -55
- package/dist/esm/router.js.map +1 -1
- package/dist/esm/scroll-restoration.js +3 -2
- package/dist/esm/scroll-restoration.js.map +1 -1
- package/package.json +3 -2
- package/src/index.ts +1 -0
- package/src/isServer.ts +24 -0
- package/src/load-matches.ts +8 -7
- package/src/new-process-route-tree.ts +12 -8
- package/src/router.ts +179 -53
- package/src/scroll-restoration.ts +3 -2
package/dist/esm/router.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Store, batch } from "@tanstack/store";
|
|
2
2
|
import { createBrowserHistory, parseHref } from "@tanstack/history";
|
|
3
|
-
import { createControlledPromise, isDangerousProtocol, deepEqual, replaceEqualDeep, decodePath, functionalUpdate,
|
|
3
|
+
import { createControlledPromise, isDangerousProtocol, deepEqual, replaceEqualDeep, last, decodePath, functionalUpdate, findLast } from "./utils.js";
|
|
4
4
|
import { processRouteTree, processRouteMasks, findSingleMatch, findRouteMatch, findFlatMatch } from "./new-process-route-tree.js";
|
|
5
5
|
import { compileDecodeCharMap, trimPath, resolvePath, cleanPath, trimPathRight, interpolatePath } from "./path.js";
|
|
6
6
|
import { createLRUCache } from "./lru-cache.js";
|
|
@@ -11,6 +11,7 @@ import { rootRouteId } from "./root.js";
|
|
|
11
11
|
import { redirect, isRedirect } from "./redirect.js";
|
|
12
12
|
import { loadMatches, loadRouteChunk, routeNeedsPreload } from "./load-matches.js";
|
|
13
13
|
import { rewriteBasepath, composeRewrites, executeRewriteInput, executeRewriteOutput } from "./rewrite.js";
|
|
14
|
+
import { isServer } from "@tanstack/router-is-server";
|
|
14
15
|
function defaultSerializeError(err) {
|
|
15
16
|
if (err instanceof Error) {
|
|
16
17
|
const obj = {
|
|
@@ -75,7 +76,7 @@ class RouterCore {
|
|
|
75
76
|
);
|
|
76
77
|
if (!this.history || this.options.history && this.options.history !== this.history) {
|
|
77
78
|
if (!this.options.history) {
|
|
78
|
-
if (!this.isServer) {
|
|
79
|
+
if (!(isServer ?? this.isServer)) {
|
|
79
80
|
this.history = createBrowserHistory();
|
|
80
81
|
}
|
|
81
82
|
} else {
|
|
@@ -84,7 +85,7 @@ class RouterCore {
|
|
|
84
85
|
}
|
|
85
86
|
this.origin = this.options.origin;
|
|
86
87
|
if (!this.origin) {
|
|
87
|
-
if (!this.isServer && window?.origin && window.origin !== "null") {
|
|
88
|
+
if (!(isServer ?? this.isServer) && window?.origin && window.origin !== "null") {
|
|
88
89
|
this.origin = window.origin;
|
|
89
90
|
} else {
|
|
90
91
|
this.origin = "http://localhost";
|
|
@@ -95,7 +96,23 @@ class RouterCore {
|
|
|
95
96
|
}
|
|
96
97
|
if (this.options.routeTree !== this.routeTree) {
|
|
97
98
|
this.routeTree = this.options.routeTree;
|
|
98
|
-
|
|
99
|
+
let processRouteTreeResult;
|
|
100
|
+
if ((isServer ?? this.isServer) && globalThis.__TSR_CACHE__ && globalThis.__TSR_CACHE__.routeTree === this.routeTree) {
|
|
101
|
+
const cached = globalThis.__TSR_CACHE__;
|
|
102
|
+
this.resolvePathCache = cached.resolvePathCache;
|
|
103
|
+
processRouteTreeResult = cached.processRouteTreeResult;
|
|
104
|
+
} else {
|
|
105
|
+
this.resolvePathCache = createLRUCache(1e3);
|
|
106
|
+
processRouteTreeResult = this.buildRouteTree();
|
|
107
|
+
if ((isServer ?? this.isServer) && globalThis.__TSR_CACHE__ === void 0) {
|
|
108
|
+
globalThis.__TSR_CACHE__ = {
|
|
109
|
+
routeTree: this.routeTree,
|
|
110
|
+
processRouteTreeResult,
|
|
111
|
+
resolvePathCache: this.resolvePathCache
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
this.setRoutes(processRouteTreeResult);
|
|
99
116
|
}
|
|
100
117
|
if (!this.__store && this.latestLocation) {
|
|
101
118
|
this.__store = new Store(getInitialRouterState(this.latestLocation), {
|
|
@@ -153,7 +170,7 @@ class RouterCore {
|
|
|
153
170
|
);
|
|
154
171
|
};
|
|
155
172
|
this.buildRouteTree = () => {
|
|
156
|
-
const
|
|
173
|
+
const result = processRouteTree(
|
|
157
174
|
this.routeTree,
|
|
158
175
|
this.options.caseSensitive,
|
|
159
176
|
(route, i) => {
|
|
@@ -163,18 +180,9 @@ class RouterCore {
|
|
|
163
180
|
}
|
|
164
181
|
);
|
|
165
182
|
if (this.options.routeMasks) {
|
|
166
|
-
processRouteMasks(this.options.routeMasks, processedTree);
|
|
167
|
-
}
|
|
168
|
-
this.routesById = routesById;
|
|
169
|
-
this.routesByPath = routesByPath;
|
|
170
|
-
this.processedTree = processedTree;
|
|
171
|
-
const notFoundRoute = this.options.notFoundRoute;
|
|
172
|
-
if (notFoundRoute) {
|
|
173
|
-
notFoundRoute.init({
|
|
174
|
-
originalIndex: 99999999999
|
|
175
|
-
});
|
|
176
|
-
this.routesById[notFoundRoute.id] = notFoundRoute;
|
|
183
|
+
processRouteMasks(this.options.routeMasks, result.processedTree);
|
|
177
184
|
}
|
|
185
|
+
return result;
|
|
178
186
|
};
|
|
179
187
|
this.subscribe = (eventType, fn) => {
|
|
180
188
|
const listener = {
|
|
@@ -229,7 +237,6 @@ class RouterCore {
|
|
|
229
237
|
}
|
|
230
238
|
return location;
|
|
231
239
|
};
|
|
232
|
-
this.resolvePathCache = createLRUCache(1e3);
|
|
233
240
|
this.resolvePathWithBase = (from, path) => {
|
|
234
241
|
const resolvedPath = resolvePath({
|
|
235
242
|
base: from,
|
|
@@ -284,26 +291,23 @@ class RouterCore {
|
|
|
284
291
|
this.buildLocation = (opts) => {
|
|
285
292
|
const build = (dest = {}) => {
|
|
286
293
|
const currentLocation = dest._fromLocation || this.pendingBuiltLocation || this.latestLocation;
|
|
287
|
-
const
|
|
288
|
-
_buildLocation: true
|
|
289
|
-
});
|
|
290
|
-
const lastMatch = last(allCurrentLocationMatches);
|
|
294
|
+
const lightweightResult = this.matchRoutesLightweight(currentLocation);
|
|
291
295
|
if (dest.from && process.env.NODE_ENV !== "production" && dest._isNavigate) {
|
|
292
296
|
const allFromMatches = this.getMatchedRoutes(dest.from).matchedRoutes;
|
|
293
|
-
const matchedFrom = findLast(
|
|
297
|
+
const matchedFrom = findLast(lightweightResult.matchedRoutes, (d) => {
|
|
294
298
|
return comparePaths(d.fullPath, dest.from);
|
|
295
299
|
});
|
|
296
300
|
const matchedCurrent = findLast(allFromMatches, (d) => {
|
|
297
|
-
return comparePaths(d.fullPath,
|
|
301
|
+
return comparePaths(d.fullPath, lightweightResult.fullPath);
|
|
298
302
|
});
|
|
299
303
|
if (!matchedFrom && !matchedCurrent) {
|
|
300
304
|
console.warn(`Could not find match for from: ${dest.from}`);
|
|
301
305
|
}
|
|
302
306
|
}
|
|
303
|
-
const defaultedFromPath = dest.unsafeRelative === "path" ? currentLocation.pathname : dest.from ??
|
|
307
|
+
const defaultedFromPath = dest.unsafeRelative === "path" ? currentLocation.pathname : dest.from ?? lightweightResult.fullPath;
|
|
304
308
|
const fromPath = this.resolvePathWithBase(defaultedFromPath, ".");
|
|
305
|
-
const fromSearch =
|
|
306
|
-
const fromParams = { ...
|
|
309
|
+
const fromSearch = lightweightResult.search;
|
|
310
|
+
const fromParams = { ...lightweightResult.params };
|
|
307
311
|
const nextTo = dest.to ? this.resolvePathWithBase(fromPath, `${dest.to}`) : this.resolvePathWithBase(fromPath, ".");
|
|
308
312
|
const nextParams = dest.params === false || dest.params === null ? {} : (dest.params ?? true) === true ? fromParams : Object.assign(
|
|
309
313
|
fromParams,
|
|
@@ -616,7 +620,7 @@ class RouterCore {
|
|
|
616
620
|
this.beforeLoad = () => {
|
|
617
621
|
this.cancelMatches();
|
|
618
622
|
this.updateLatestLocation();
|
|
619
|
-
if (this.isServer) {
|
|
623
|
+
if (isServer ?? this.isServer) {
|
|
620
624
|
const nextLocation = this.buildLocation({
|
|
621
625
|
to: this.latestLocation.pathname,
|
|
622
626
|
search: true,
|
|
@@ -736,7 +740,7 @@ class RouterCore {
|
|
|
736
740
|
} catch (err) {
|
|
737
741
|
if (isRedirect(err)) {
|
|
738
742
|
redirect2 = err;
|
|
739
|
-
if (!this.isServer) {
|
|
743
|
+
if (!(isServer ?? this.isServer)) {
|
|
740
744
|
this.navigate({
|
|
741
745
|
...redirect2.options,
|
|
742
746
|
replace: true,
|
|
@@ -1032,6 +1036,22 @@ class RouterCore {
|
|
|
1032
1036
|
get state() {
|
|
1033
1037
|
return this.__store.state;
|
|
1034
1038
|
}
|
|
1039
|
+
setRoutes({
|
|
1040
|
+
routesById,
|
|
1041
|
+
routesByPath,
|
|
1042
|
+
processedTree
|
|
1043
|
+
}) {
|
|
1044
|
+
this.routesById = routesById;
|
|
1045
|
+
this.routesByPath = routesByPath;
|
|
1046
|
+
this.processedTree = processedTree;
|
|
1047
|
+
const notFoundRoute = this.options.notFoundRoute;
|
|
1048
|
+
if (notFoundRoute) {
|
|
1049
|
+
notFoundRoute.init({
|
|
1050
|
+
originalIndex: 99999999999
|
|
1051
|
+
});
|
|
1052
|
+
this.routesById[notFoundRoute.id] = notFoundRoute;
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1035
1055
|
get looseRoutesById() {
|
|
1036
1056
|
return this.routesById;
|
|
1037
1057
|
}
|
|
@@ -1110,32 +1130,18 @@ class RouterCore {
|
|
|
1110
1130
|
const strictParams = existingMatch?._strictParams ?? usedParams;
|
|
1111
1131
|
let paramsError = void 0;
|
|
1112
1132
|
if (!existingMatch) {
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1133
|
+
try {
|
|
1134
|
+
extractStrictParams(route, usedParams, parsedParams, strictParams);
|
|
1135
|
+
} catch (err) {
|
|
1136
|
+
if (isNotFound(err) || isRedirect(err)) {
|
|
1137
|
+
paramsError = err;
|
|
1138
|
+
} else {
|
|
1139
|
+
paramsError = new PathParamError(err.message, {
|
|
1140
|
+
cause: err
|
|
1141
|
+
});
|
|
1118
1142
|
}
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
if (strictParseParams) {
|
|
1122
|
-
try {
|
|
1123
|
-
Object.assign(
|
|
1124
|
-
strictParams,
|
|
1125
|
-
strictParseParams(strictParams)
|
|
1126
|
-
);
|
|
1127
|
-
} catch (err) {
|
|
1128
|
-
if (isNotFound(err) || isRedirect(err)) {
|
|
1129
|
-
paramsError = err;
|
|
1130
|
-
} else {
|
|
1131
|
-
paramsError = new PathParamError(err.message, {
|
|
1132
|
-
cause: err
|
|
1133
|
-
});
|
|
1134
|
-
}
|
|
1135
|
-
if (opts?.throwOnError) {
|
|
1136
|
-
throw paramsError;
|
|
1137
|
-
}
|
|
1138
|
-
}
|
|
1143
|
+
if (opts?.throwOnError) {
|
|
1144
|
+
throw paramsError;
|
|
1139
1145
|
}
|
|
1140
1146
|
}
|
|
1141
1147
|
}
|
|
@@ -1155,7 +1161,7 @@ class RouterCore {
|
|
|
1155
1161
|
const status = route.options.loader || route.options.beforeLoad || route.lazyFn || routeNeedsPreload(route) ? "pending" : "success";
|
|
1156
1162
|
match = {
|
|
1157
1163
|
id: matchId,
|
|
1158
|
-
ssr: this.isServer ? void 0 : route.options.ssr,
|
|
1164
|
+
ssr: isServer ?? this.isServer ? void 0 : route.options.ssr,
|
|
1159
1165
|
index,
|
|
1160
1166
|
routeId: route.id,
|
|
1161
1167
|
params: previousMatch ? replaceEqualDeep(previousMatch.params, routeParams) : routeParams,
|
|
@@ -1204,7 +1210,7 @@ class RouterCore {
|
|
|
1204
1210
|
matches.forEach((match, index) => {
|
|
1205
1211
|
const route = this.looseRoutesById[match.routeId];
|
|
1206
1212
|
const existingMatch = this.getMatch(match.id);
|
|
1207
|
-
if (!existingMatch
|
|
1213
|
+
if (!existingMatch) {
|
|
1208
1214
|
const parentMatch = matches[index - 1];
|
|
1209
1215
|
const parentContext = getParentContext(parentMatch);
|
|
1210
1216
|
if (route.options.context) {
|
|
@@ -1231,6 +1237,53 @@ class RouterCore {
|
|
|
1231
1237
|
});
|
|
1232
1238
|
return matches;
|
|
1233
1239
|
}
|
|
1240
|
+
/**
|
|
1241
|
+
* Lightweight route matching for buildLocation.
|
|
1242
|
+
* Only computes fullPath, accumulated search, and params - skipping expensive
|
|
1243
|
+
* operations like AbortController, ControlledPromise, loaderDeps, and full match objects.
|
|
1244
|
+
*/
|
|
1245
|
+
matchRoutesLightweight(location) {
|
|
1246
|
+
const { matchedRoutes, routeParams, parsedParams } = this.getMatchedRoutes(
|
|
1247
|
+
location.pathname
|
|
1248
|
+
);
|
|
1249
|
+
const lastRoute = last(matchedRoutes);
|
|
1250
|
+
const accumulatedSearch = { ...location.search };
|
|
1251
|
+
for (const route of matchedRoutes) {
|
|
1252
|
+
try {
|
|
1253
|
+
Object.assign(
|
|
1254
|
+
accumulatedSearch,
|
|
1255
|
+
validateSearch(route.options.validateSearch, accumulatedSearch)
|
|
1256
|
+
);
|
|
1257
|
+
} catch {
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
const lastStateMatch = last(this.state.matches);
|
|
1261
|
+
const canReuseParams = lastStateMatch && lastStateMatch.routeId === lastRoute.id && location.pathname === this.state.location.pathname;
|
|
1262
|
+
let params;
|
|
1263
|
+
if (canReuseParams) {
|
|
1264
|
+
params = lastStateMatch.params;
|
|
1265
|
+
} else {
|
|
1266
|
+
const strictParams = { ...routeParams };
|
|
1267
|
+
for (const route of matchedRoutes) {
|
|
1268
|
+
try {
|
|
1269
|
+
extractStrictParams(
|
|
1270
|
+
route,
|
|
1271
|
+
routeParams,
|
|
1272
|
+
parsedParams ?? {},
|
|
1273
|
+
strictParams
|
|
1274
|
+
);
|
|
1275
|
+
} catch {
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
params = strictParams;
|
|
1279
|
+
}
|
|
1280
|
+
return {
|
|
1281
|
+
matchedRoutes,
|
|
1282
|
+
fullPath: lastRoute.fullPath,
|
|
1283
|
+
search: accumulatedSearch,
|
|
1284
|
+
params
|
|
1285
|
+
};
|
|
1286
|
+
}
|
|
1234
1287
|
}
|
|
1235
1288
|
class SearchParamError extends Error {
|
|
1236
1289
|
}
|
|
@@ -1393,6 +1446,21 @@ function findGlobalNotFoundRouteId(notFoundMode, routes) {
|
|
|
1393
1446
|
}
|
|
1394
1447
|
return rootRouteId;
|
|
1395
1448
|
}
|
|
1449
|
+
function extractStrictParams(route, referenceParams, parsedParams, accumulatedParams) {
|
|
1450
|
+
const parseParams = route.options.params?.parse ?? route.options.parseParams;
|
|
1451
|
+
if (parseParams) {
|
|
1452
|
+
if (route.options.skipRouteOnParseError) {
|
|
1453
|
+
for (const key in referenceParams) {
|
|
1454
|
+
if (key in parsedParams) {
|
|
1455
|
+
accumulatedParams[key] = parsedParams[key];
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
} else {
|
|
1459
|
+
const result = parseParams(accumulatedParams);
|
|
1460
|
+
Object.assign(accumulatedParams, result);
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1396
1464
|
export {
|
|
1397
1465
|
PathParamError,
|
|
1398
1466
|
RouterCore,
|