@tanstack/router-core 1.155.0 → 1.156.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.
@@ -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, last, findLast } from "./utils.js";
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";
@@ -95,7 +95,23 @@ class RouterCore {
95
95
  }
96
96
  if (this.options.routeTree !== this.routeTree) {
97
97
  this.routeTree = this.options.routeTree;
98
- this.buildRouteTree();
98
+ let processRouteTreeResult;
99
+ if (this.isServer && globalThis.__TSR_CACHE__ && globalThis.__TSR_CACHE__.routeTree === this.routeTree) {
100
+ const cached = globalThis.__TSR_CACHE__;
101
+ this.resolvePathCache = cached.resolvePathCache;
102
+ processRouteTreeResult = cached.processRouteTreeResult;
103
+ } else {
104
+ this.resolvePathCache = createLRUCache(1e3);
105
+ processRouteTreeResult = this.buildRouteTree();
106
+ if (this.isServer && globalThis.__TSR_CACHE__ === void 0) {
107
+ globalThis.__TSR_CACHE__ = {
108
+ routeTree: this.routeTree,
109
+ processRouteTreeResult,
110
+ resolvePathCache: this.resolvePathCache
111
+ };
112
+ }
113
+ }
114
+ this.setRoutes(processRouteTreeResult);
99
115
  }
100
116
  if (!this.__store && this.latestLocation) {
101
117
  this.__store = new Store(getInitialRouterState(this.latestLocation), {
@@ -153,7 +169,7 @@ class RouterCore {
153
169
  );
154
170
  };
155
171
  this.buildRouteTree = () => {
156
- const { routesById, routesByPath, processedTree } = processRouteTree(
172
+ const result = processRouteTree(
157
173
  this.routeTree,
158
174
  this.options.caseSensitive,
159
175
  (route, i) => {
@@ -163,18 +179,9 @@ class RouterCore {
163
179
  }
164
180
  );
165
181
  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;
182
+ processRouteMasks(this.options.routeMasks, result.processedTree);
177
183
  }
184
+ return result;
178
185
  };
179
186
  this.subscribe = (eventType, fn) => {
180
187
  const listener = {
@@ -229,7 +236,6 @@ class RouterCore {
229
236
  }
230
237
  return location;
231
238
  };
232
- this.resolvePathCache = createLRUCache(1e3);
233
239
  this.resolvePathWithBase = (from, path) => {
234
240
  const resolvedPath = resolvePath({
235
241
  base: from,
@@ -284,26 +290,23 @@ class RouterCore {
284
290
  this.buildLocation = (opts) => {
285
291
  const build = (dest = {}) => {
286
292
  const currentLocation = dest._fromLocation || this.pendingBuiltLocation || this.latestLocation;
287
- const allCurrentLocationMatches = this.matchRoutes(currentLocation, {
288
- _buildLocation: true
289
- });
290
- const lastMatch = last(allCurrentLocationMatches);
293
+ const lightweightResult = this.matchRoutesLightweight(currentLocation);
291
294
  if (dest.from && process.env.NODE_ENV !== "production" && dest._isNavigate) {
292
295
  const allFromMatches = this.getMatchedRoutes(dest.from).matchedRoutes;
293
- const matchedFrom = findLast(allCurrentLocationMatches, (d) => {
296
+ const matchedFrom = findLast(lightweightResult.matchedRoutes, (d) => {
294
297
  return comparePaths(d.fullPath, dest.from);
295
298
  });
296
299
  const matchedCurrent = findLast(allFromMatches, (d) => {
297
- return comparePaths(d.fullPath, lastMatch.fullPath);
300
+ return comparePaths(d.fullPath, lightweightResult.fullPath);
298
301
  });
299
302
  if (!matchedFrom && !matchedCurrent) {
300
303
  console.warn(`Could not find match for from: ${dest.from}`);
301
304
  }
302
305
  }
303
- const defaultedFromPath = dest.unsafeRelative === "path" ? currentLocation.pathname : dest.from ?? lastMatch.fullPath;
306
+ const defaultedFromPath = dest.unsafeRelative === "path" ? currentLocation.pathname : dest.from ?? lightweightResult.fullPath;
304
307
  const fromPath = this.resolvePathWithBase(defaultedFromPath, ".");
305
- const fromSearch = lastMatch.search;
306
- const fromParams = { ...lastMatch.params };
308
+ const fromSearch = lightweightResult.search;
309
+ const fromParams = { ...lightweightResult.params };
307
310
  const nextTo = dest.to ? this.resolvePathWithBase(fromPath, `${dest.to}`) : this.resolvePathWithBase(fromPath, ".");
308
311
  const nextParams = dest.params === false || dest.params === null ? {} : (dest.params ?? true) === true ? fromParams : Object.assign(
309
312
  fromParams,
@@ -1032,6 +1035,22 @@ class RouterCore {
1032
1035
  get state() {
1033
1036
  return this.__store.state;
1034
1037
  }
1038
+ setRoutes({
1039
+ routesById,
1040
+ routesByPath,
1041
+ processedTree
1042
+ }) {
1043
+ this.routesById = routesById;
1044
+ this.routesByPath = routesByPath;
1045
+ this.processedTree = processedTree;
1046
+ const notFoundRoute = this.options.notFoundRoute;
1047
+ if (notFoundRoute) {
1048
+ notFoundRoute.init({
1049
+ originalIndex: 99999999999
1050
+ });
1051
+ this.routesById[notFoundRoute.id] = notFoundRoute;
1052
+ }
1053
+ }
1035
1054
  get looseRoutesById() {
1036
1055
  return this.routesById;
1037
1056
  }
@@ -1110,32 +1129,18 @@ class RouterCore {
1110
1129
  const strictParams = existingMatch?._strictParams ?? usedParams;
1111
1130
  let paramsError = void 0;
1112
1131
  if (!existingMatch) {
1113
- if (route.options.skipRouteOnParseError) {
1114
- for (const key in usedParams) {
1115
- if (key in parsedParams) {
1116
- strictParams[key] = parsedParams[key];
1117
- }
1132
+ try {
1133
+ extractStrictParams(route, usedParams, parsedParams, strictParams);
1134
+ } catch (err) {
1135
+ if (isNotFound(err) || isRedirect(err)) {
1136
+ paramsError = err;
1137
+ } else {
1138
+ paramsError = new PathParamError(err.message, {
1139
+ cause: err
1140
+ });
1118
1141
  }
1119
- } else {
1120
- const strictParseParams = route.options.params?.parse ?? route.options.parseParams;
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
- }
1142
+ if (opts?.throwOnError) {
1143
+ throw paramsError;
1139
1144
  }
1140
1145
  }
1141
1146
  }
@@ -1204,7 +1209,7 @@ class RouterCore {
1204
1209
  matches.forEach((match, index) => {
1205
1210
  const route = this.looseRoutesById[match.routeId];
1206
1211
  const existingMatch = this.getMatch(match.id);
1207
- if (!existingMatch && opts?._buildLocation !== true) {
1212
+ if (!existingMatch) {
1208
1213
  const parentMatch = matches[index - 1];
1209
1214
  const parentContext = getParentContext(parentMatch);
1210
1215
  if (route.options.context) {
@@ -1231,6 +1236,53 @@ class RouterCore {
1231
1236
  });
1232
1237
  return matches;
1233
1238
  }
1239
+ /**
1240
+ * Lightweight route matching for buildLocation.
1241
+ * Only computes fullPath, accumulated search, and params - skipping expensive
1242
+ * operations like AbortController, ControlledPromise, loaderDeps, and full match objects.
1243
+ */
1244
+ matchRoutesLightweight(location) {
1245
+ const { matchedRoutes, routeParams, parsedParams } = this.getMatchedRoutes(
1246
+ location.pathname
1247
+ );
1248
+ const lastRoute = last(matchedRoutes);
1249
+ const accumulatedSearch = { ...location.search };
1250
+ for (const route of matchedRoutes) {
1251
+ try {
1252
+ Object.assign(
1253
+ accumulatedSearch,
1254
+ validateSearch(route.options.validateSearch, accumulatedSearch)
1255
+ );
1256
+ } catch {
1257
+ }
1258
+ }
1259
+ const lastStateMatch = last(this.state.matches);
1260
+ const canReuseParams = lastStateMatch && lastStateMatch.routeId === lastRoute.id && location.pathname === this.state.location.pathname;
1261
+ let params;
1262
+ if (canReuseParams) {
1263
+ params = lastStateMatch.params;
1264
+ } else {
1265
+ const strictParams = { ...routeParams };
1266
+ for (const route of matchedRoutes) {
1267
+ try {
1268
+ extractStrictParams(
1269
+ route,
1270
+ routeParams,
1271
+ parsedParams ?? {},
1272
+ strictParams
1273
+ );
1274
+ } catch {
1275
+ }
1276
+ }
1277
+ params = strictParams;
1278
+ }
1279
+ return {
1280
+ matchedRoutes,
1281
+ fullPath: lastRoute.fullPath,
1282
+ search: accumulatedSearch,
1283
+ params
1284
+ };
1285
+ }
1234
1286
  }
1235
1287
  class SearchParamError extends Error {
1236
1288
  }
@@ -1393,6 +1445,21 @@ function findGlobalNotFoundRouteId(notFoundMode, routes) {
1393
1445
  }
1394
1446
  return rootRouteId;
1395
1447
  }
1448
+ function extractStrictParams(route, referenceParams, parsedParams, accumulatedParams) {
1449
+ const parseParams = route.options.params?.parse ?? route.options.parseParams;
1450
+ if (parseParams) {
1451
+ if (route.options.skipRouteOnParseError) {
1452
+ for (const key in referenceParams) {
1453
+ if (key in parsedParams) {
1454
+ accumulatedParams[key] = parsedParams[key];
1455
+ }
1456
+ }
1457
+ } else {
1458
+ const result = parseParams(accumulatedParams);
1459
+ Object.assign(accumulatedParams, result);
1460
+ }
1461
+ }
1462
+ }
1396
1463
  export {
1397
1464
  PathParamError,
1398
1465
  RouterCore,