@tanstack/router-core 1.136.3 → 1.136.5
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 +2 -0
- package/dist/cjs/index.cjs +0 -5
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +1 -4
- package/dist/cjs/lru-cache.cjs +5 -0
- package/dist/cjs/lru-cache.cjs.map +1 -1
- package/dist/cjs/lru-cache.d.cts +1 -0
- package/dist/cjs/new-process-route-tree.cjs +655 -0
- package/dist/cjs/new-process-route-tree.cjs.map +1 -0
- package/dist/cjs/new-process-route-tree.d.cts +177 -0
- package/dist/cjs/path.cjs +133 -434
- package/dist/cjs/path.cjs.map +1 -1
- package/dist/cjs/path.d.cts +3 -39
- package/dist/cjs/router.cjs +47 -98
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/router.d.cts +7 -11
- package/dist/cjs/ssr/constants.cjs.map +1 -1
- package/dist/cjs/ssr/constants.d.cts +1 -0
- package/dist/cjs/ssr/ssr-client.cjs +2 -0
- package/dist/cjs/ssr/ssr-client.cjs.map +1 -1
- package/dist/cjs/ssr/ssr-client.d.cts +4 -1
- package/dist/cjs/ssr/ssr-server.cjs +64 -12
- package/dist/cjs/ssr/ssr-server.cjs.map +1 -1
- package/dist/cjs/ssr/tsrScript.cjs +1 -1
- package/dist/cjs/ssr/tsrScript.cjs.map +1 -1
- package/dist/esm/Matches.d.ts +2 -0
- package/dist/esm/Matches.js.map +1 -1
- package/dist/esm/index.d.ts +1 -4
- package/dist/esm/index.js +1 -6
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lru-cache.d.ts +1 -0
- package/dist/esm/lru-cache.js +5 -0
- package/dist/esm/lru-cache.js.map +1 -1
- package/dist/esm/new-process-route-tree.d.ts +177 -0
- package/dist/esm/new-process-route-tree.js +655 -0
- package/dist/esm/new-process-route-tree.js.map +1 -0
- package/dist/esm/path.d.ts +3 -39
- package/dist/esm/path.js +133 -434
- package/dist/esm/path.js.map +1 -1
- package/dist/esm/router.d.ts +7 -11
- package/dist/esm/router.js +48 -99
- package/dist/esm/router.js.map +1 -1
- package/dist/esm/ssr/constants.d.ts +1 -0
- package/dist/esm/ssr/constants.js.map +1 -1
- package/dist/esm/ssr/ssr-client.d.ts +4 -1
- package/dist/esm/ssr/ssr-client.js +2 -0
- package/dist/esm/ssr/ssr-client.js.map +1 -1
- package/dist/esm/ssr/ssr-server.js +64 -12
- package/dist/esm/ssr/ssr-server.js.map +1 -1
- package/dist/esm/ssr/tsrScript.js +1 -1
- package/dist/esm/ssr/tsrScript.js.map +1 -1
- package/package.json +1 -1
- package/src/Matches.ts +2 -0
- package/src/index.ts +0 -6
- package/src/lru-cache.ts +6 -0
- package/src/new-process-route-tree.ts +1036 -0
- package/src/path.ts +168 -639
- package/src/router.ts +58 -126
- package/src/ssr/constants.ts +1 -0
- package/src/ssr/ssr-client.ts +10 -1
- package/src/ssr/ssr-server.ts +69 -12
- package/src/ssr/tsrScript.ts +4 -0
- package/dist/cjs/process-route-tree.cjs +0 -144
- package/dist/cjs/process-route-tree.cjs.map +0 -1
- package/dist/cjs/process-route-tree.d.cts +0 -18
- package/dist/esm/process-route-tree.d.ts +0 -18
- package/dist/esm/process-route-tree.js +0 -144
- package/dist/esm/process-route-tree.js.map +0 -1
- package/src/process-route-tree.ts +0 -241
package/src/router.ts
CHANGED
|
@@ -9,21 +9,26 @@ import {
|
|
|
9
9
|
last,
|
|
10
10
|
replaceEqualDeep,
|
|
11
11
|
} from './utils'
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
findFlatMatch,
|
|
14
|
+
findRouteMatch,
|
|
15
|
+
findSingleMatch,
|
|
16
|
+
processRouteMasks,
|
|
17
|
+
processRouteTree,
|
|
18
|
+
} from './new-process-route-tree'
|
|
13
19
|
import {
|
|
14
20
|
cleanPath,
|
|
15
21
|
interpolatePath,
|
|
16
|
-
matchPathname,
|
|
17
22
|
resolvePath,
|
|
18
23
|
trimPath,
|
|
19
24
|
trimPathRight,
|
|
20
25
|
} from './path'
|
|
26
|
+
import { createLRUCache } from './lru-cache'
|
|
21
27
|
import { isNotFound } from './not-found'
|
|
22
28
|
import { setupScrollRestoration } from './scroll-restoration'
|
|
23
29
|
import { defaultParseSearch, defaultStringifySearch } from './searchParams'
|
|
24
30
|
import { rootRouteId } from './root'
|
|
25
31
|
import { isRedirect, redirect } from './redirect'
|
|
26
|
-
import { createLRUCache } from './lru-cache'
|
|
27
32
|
import { loadMatches, loadRouteChunk, routeNeedsPreload } from './load-matches'
|
|
28
33
|
import {
|
|
29
34
|
composeRewrites,
|
|
@@ -31,7 +36,7 @@ import {
|
|
|
31
36
|
executeRewriteOutput,
|
|
32
37
|
rewriteBasepath,
|
|
33
38
|
} from './rewrite'
|
|
34
|
-
import type {
|
|
39
|
+
import type { ProcessedTree } from './new-process-route-tree'
|
|
35
40
|
import type { SearchParser, SearchSerializer } from './searchParams'
|
|
36
41
|
import type { AnyRedirect, ResolvedRedirect } from './redirect'
|
|
37
42
|
import type {
|
|
@@ -691,10 +696,7 @@ export type ParseLocationFn<TRouteTree extends AnyRoute> = (
|
|
|
691
696
|
previousLocation?: ParsedLocation<FullSearchSchema<TRouteTree>>,
|
|
692
697
|
) => ParsedLocation<FullSearchSchema<TRouteTree>>
|
|
693
698
|
|
|
694
|
-
export type GetMatchRoutesFn = (
|
|
695
|
-
pathname: string,
|
|
696
|
-
routePathname: string | undefined,
|
|
697
|
-
) => {
|
|
699
|
+
export type GetMatchRoutesFn = (pathname: string) => {
|
|
698
700
|
matchedRoutes: Array<AnyRoute>
|
|
699
701
|
routeParams: Record<string, string>
|
|
700
702
|
foundRoute: AnyRoute | undefined
|
|
@@ -754,6 +756,7 @@ export interface ServerSsr {
|
|
|
754
756
|
isDehydrated: () => boolean
|
|
755
757
|
onRenderFinished: (listener: () => void) => void
|
|
756
758
|
dehydrate: () => Promise<void>
|
|
759
|
+
takeBufferedScripts: () => string | undefined
|
|
757
760
|
}
|
|
758
761
|
|
|
759
762
|
export type AnyRouterWithContext<TContext> = RouterCore<
|
|
@@ -901,7 +904,7 @@ export class RouterCore<
|
|
|
901
904
|
routeTree!: TRouteTree
|
|
902
905
|
routesById!: RoutesById<TRouteTree>
|
|
903
906
|
routesByPath!: RoutesByPath<TRouteTree>
|
|
904
|
-
|
|
907
|
+
processedTree!: ProcessedTree<TRouteTree, any, any>
|
|
905
908
|
isServer!: boolean
|
|
906
909
|
pathParamsDecodeCharMap?: Map<string, string>
|
|
907
910
|
|
|
@@ -1093,18 +1096,22 @@ export class RouterCore<
|
|
|
1093
1096
|
}
|
|
1094
1097
|
|
|
1095
1098
|
buildRouteTree = () => {
|
|
1096
|
-
const { routesById, routesByPath,
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
+
const { routesById, routesByPath, processedTree } = processRouteTree(
|
|
1100
|
+
this.routeTree,
|
|
1101
|
+
this.options.caseSensitive,
|
|
1102
|
+
(route, i) => {
|
|
1099
1103
|
route.init({
|
|
1100
1104
|
originalIndex: i,
|
|
1101
1105
|
})
|
|
1102
1106
|
},
|
|
1103
|
-
|
|
1107
|
+
)
|
|
1108
|
+
if (this.options.routeMasks) {
|
|
1109
|
+
processRouteMasks(this.options.routeMasks, processedTree)
|
|
1110
|
+
}
|
|
1104
1111
|
|
|
1105
1112
|
this.routesById = routesById as RoutesById<TRouteTree>
|
|
1106
1113
|
this.routesByPath = routesByPath as RoutesByPath<TRouteTree>
|
|
1107
|
-
this.
|
|
1114
|
+
this.processedTree = processedTree
|
|
1108
1115
|
|
|
1109
1116
|
const notFoundRoute = this.options.notFoundRoute
|
|
1110
1117
|
|
|
@@ -1202,13 +1209,15 @@ export class RouterCore<
|
|
|
1202
1209
|
return location
|
|
1203
1210
|
}
|
|
1204
1211
|
|
|
1212
|
+
resolvePathCache = createLRUCache<string, string>(1000)
|
|
1213
|
+
|
|
1205
1214
|
/** Resolve a path against the router basepath and trailing-slash policy. */
|
|
1206
1215
|
resolvePathWithBase = (from: string, path: string) => {
|
|
1207
1216
|
const resolvedPath = resolvePath({
|
|
1208
1217
|
base: from,
|
|
1209
1218
|
to: cleanPath(path),
|
|
1210
1219
|
trailingSlash: this.options.trailingSlash,
|
|
1211
|
-
|
|
1220
|
+
cache: this.resolvePathCache,
|
|
1212
1221
|
})
|
|
1213
1222
|
return resolvedPath
|
|
1214
1223
|
}
|
|
@@ -1241,7 +1250,6 @@ export class RouterCore<
|
|
|
1241
1250
|
): Array<AnyRouteMatch> {
|
|
1242
1251
|
const { foundRoute, matchedRoutes, routeParams } = this.getMatchedRoutes(
|
|
1243
1252
|
next.pathname,
|
|
1244
|
-
opts?.dest?.to as string,
|
|
1245
1253
|
)
|
|
1246
1254
|
let isGlobalNotFound = false
|
|
1247
1255
|
|
|
@@ -1534,21 +1542,11 @@ export class RouterCore<
|
|
|
1534
1542
|
return matches
|
|
1535
1543
|
}
|
|
1536
1544
|
|
|
1537
|
-
|
|
1538
|
-
private parsePathnameCache: ParsePathnameCache = createLRUCache(1000)
|
|
1539
|
-
|
|
1540
|
-
getMatchedRoutes: GetMatchRoutesFn = (
|
|
1541
|
-
pathname: string,
|
|
1542
|
-
routePathname: string | undefined,
|
|
1543
|
-
) => {
|
|
1545
|
+
getMatchedRoutes: GetMatchRoutesFn = (pathname) => {
|
|
1544
1546
|
return getMatchedRoutes({
|
|
1545
1547
|
pathname,
|
|
1546
|
-
routePathname,
|
|
1547
|
-
caseSensitive: this.options.caseSensitive,
|
|
1548
|
-
routesByPath: this.routesByPath,
|
|
1549
1548
|
routesById: this.routesById,
|
|
1550
|
-
|
|
1551
|
-
parseCache: this.parsePathnameCache,
|
|
1549
|
+
processedTree: this.processedTree,
|
|
1552
1550
|
})
|
|
1553
1551
|
}
|
|
1554
1552
|
|
|
@@ -1611,10 +1609,7 @@ export class RouterCore<
|
|
|
1611
1609
|
process.env.NODE_ENV !== 'production' &&
|
|
1612
1610
|
dest._isNavigate
|
|
1613
1611
|
) {
|
|
1614
|
-
const allFromMatches = this.getMatchedRoutes(
|
|
1615
|
-
dest.from,
|
|
1616
|
-
undefined,
|
|
1617
|
-
).matchedRoutes
|
|
1612
|
+
const allFromMatches = this.getMatchedRoutes(dest.from).matchedRoutes
|
|
1618
1613
|
|
|
1619
1614
|
const matchedFrom = findLast(allCurrentLocationMatches, (d) => {
|
|
1620
1615
|
return comparePaths(d.fullPath, dest.from!)
|
|
@@ -1665,7 +1660,6 @@ export class RouterCore<
|
|
|
1665
1660
|
const interpolatedNextTo = interpolatePath({
|
|
1666
1661
|
path: nextTo,
|
|
1667
1662
|
params: nextParams,
|
|
1668
|
-
parseCache: this.parsePathnameCache,
|
|
1669
1663
|
}).interpolatedPath
|
|
1670
1664
|
|
|
1671
1665
|
const destRoutes = this.matchRoutes(interpolatedNextTo, undefined, {
|
|
@@ -1692,7 +1686,6 @@ export class RouterCore<
|
|
|
1692
1686
|
path: nextTo,
|
|
1693
1687
|
params: nextParams,
|
|
1694
1688
|
decodeCharMap: this.pathParamsDecodeCharMap,
|
|
1695
|
-
parseCache: this.parsePathnameCache,
|
|
1696
1689
|
}).interpolatedPath,
|
|
1697
1690
|
)
|
|
1698
1691
|
|
|
@@ -1785,35 +1778,23 @@ export class RouterCore<
|
|
|
1785
1778
|
let maskedNext = maskedDest ? build(maskedDest) : undefined
|
|
1786
1779
|
|
|
1787
1780
|
if (!maskedNext) {
|
|
1788
|
-
|
|
1781
|
+
const params = {}
|
|
1789
1782
|
|
|
1790
|
-
|
|
1791
|
-
const match =
|
|
1783
|
+
if (this.options.routeMasks) {
|
|
1784
|
+
const match = findFlatMatch<RouteMask<TRouteTree>>(
|
|
1792
1785
|
next.pathname,
|
|
1793
|
-
|
|
1794
|
-
to: d.from,
|
|
1795
|
-
caseSensitive: false,
|
|
1796
|
-
fuzzy: false,
|
|
1797
|
-
},
|
|
1798
|
-
this.parsePathnameCache,
|
|
1786
|
+
this.processedTree,
|
|
1799
1787
|
)
|
|
1800
|
-
|
|
1801
1788
|
if (match) {
|
|
1802
|
-
params
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
const { from: _from, ...maskProps } = foundMask
|
|
1811
|
-
maskedDest = {
|
|
1812
|
-
from: opts.from,
|
|
1813
|
-
...maskProps,
|
|
1814
|
-
params,
|
|
1789
|
+
Object.assign(params, match.params) // Copy params, because they're cached
|
|
1790
|
+
const { from: _from, ...maskProps } = match.route
|
|
1791
|
+
maskedDest = {
|
|
1792
|
+
from: opts.from,
|
|
1793
|
+
...maskProps,
|
|
1794
|
+
params,
|
|
1795
|
+
}
|
|
1796
|
+
maskedNext = build(maskedDest)
|
|
1815
1797
|
}
|
|
1816
|
-
maskedNext = build(maskedDest)
|
|
1817
1798
|
}
|
|
1818
1799
|
}
|
|
1819
1800
|
|
|
@@ -2524,31 +2505,31 @@ export class RouterCore<
|
|
|
2524
2505
|
? this.latestLocation
|
|
2525
2506
|
: this.state.resolvedLocation || this.state.location
|
|
2526
2507
|
|
|
2527
|
-
const match =
|
|
2508
|
+
const match = findSingleMatch(
|
|
2509
|
+
next.pathname,
|
|
2510
|
+
opts?.caseSensitive ?? false,
|
|
2511
|
+
opts?.fuzzy ?? false,
|
|
2528
2512
|
baseLocation.pathname,
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
to: next.pathname,
|
|
2532
|
-
},
|
|
2533
|
-
this.parsePathnameCache,
|
|
2534
|
-
) as any
|
|
2513
|
+
this.processedTree,
|
|
2514
|
+
)
|
|
2535
2515
|
|
|
2536
2516
|
if (!match) {
|
|
2537
2517
|
return false
|
|
2538
2518
|
}
|
|
2519
|
+
|
|
2539
2520
|
if (location.params) {
|
|
2540
|
-
if (!deepEqual(match, location.params, { partial: true })) {
|
|
2521
|
+
if (!deepEqual(match.params, location.params, { partial: true })) {
|
|
2541
2522
|
return false
|
|
2542
2523
|
}
|
|
2543
2524
|
}
|
|
2544
2525
|
|
|
2545
|
-
if (
|
|
2526
|
+
if (opts?.includeSearch ?? true) {
|
|
2546
2527
|
return deepEqual(baseLocation.search, next.search, { partial: true })
|
|
2547
|
-
? match
|
|
2528
|
+
? match.params
|
|
2548
2529
|
: false
|
|
2549
2530
|
}
|
|
2550
2531
|
|
|
2551
|
-
return match
|
|
2532
|
+
return match.params
|
|
2552
2533
|
}
|
|
2553
2534
|
|
|
2554
2535
|
ssr?: {
|
|
@@ -2644,70 +2625,21 @@ function validateSearch(validateSearch: AnyValidator, input: unknown): unknown {
|
|
|
2644
2625
|
*/
|
|
2645
2626
|
export function getMatchedRoutes<TRouteLike extends RouteLike>({
|
|
2646
2627
|
pathname,
|
|
2647
|
-
routePathname,
|
|
2648
|
-
caseSensitive,
|
|
2649
|
-
routesByPath,
|
|
2650
2628
|
routesById,
|
|
2651
|
-
|
|
2652
|
-
parseCache,
|
|
2629
|
+
processedTree,
|
|
2653
2630
|
}: {
|
|
2654
2631
|
pathname: string
|
|
2655
|
-
routePathname?: string
|
|
2656
|
-
caseSensitive?: boolean
|
|
2657
|
-
routesByPath: Record<string, TRouteLike>
|
|
2658
2632
|
routesById: Record<string, TRouteLike>
|
|
2659
|
-
|
|
2660
|
-
parseCache?: ParsePathnameCache
|
|
2633
|
+
processedTree: ProcessedTree<any, any, any>
|
|
2661
2634
|
}) {
|
|
2662
|
-
|
|
2635
|
+
const routeParams: Record<string, string> = {}
|
|
2663
2636
|
const trimmedPath = trimPathRight(pathname)
|
|
2664
|
-
const getMatchedParams = (route: TRouteLike) => {
|
|
2665
|
-
const result = matchPathname(
|
|
2666
|
-
trimmedPath,
|
|
2667
|
-
{
|
|
2668
|
-
to: route.fullPath,
|
|
2669
|
-
caseSensitive: route.options?.caseSensitive ?? caseSensitive,
|
|
2670
|
-
// we need fuzzy matching for `notFoundMode: 'fuzzy'`
|
|
2671
|
-
fuzzy: true,
|
|
2672
|
-
},
|
|
2673
|
-
parseCache,
|
|
2674
|
-
)
|
|
2675
|
-
return result
|
|
2676
|
-
}
|
|
2677
2637
|
|
|
2678
|
-
let foundRoute: TRouteLike | undefined =
|
|
2679
|
-
|
|
2680
|
-
if (
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
// iterate over flatRoutes to find the best match
|
|
2684
|
-
// if we find a fuzzy matching route, keep looking for a perfect fit
|
|
2685
|
-
let fuzzyMatch:
|
|
2686
|
-
| { foundRoute: TRouteLike; routeParams: Record<string, string> }
|
|
2687
|
-
| undefined = undefined
|
|
2688
|
-
for (const route of flatRoutes) {
|
|
2689
|
-
const matchedParams = getMatchedParams(route)
|
|
2690
|
-
|
|
2691
|
-
if (matchedParams) {
|
|
2692
|
-
if (
|
|
2693
|
-
route.path !== '/' &&
|
|
2694
|
-
(matchedParams as Record<string, string>)['**']
|
|
2695
|
-
) {
|
|
2696
|
-
if (!fuzzyMatch) {
|
|
2697
|
-
fuzzyMatch = { foundRoute: route, routeParams: matchedParams }
|
|
2698
|
-
}
|
|
2699
|
-
} else {
|
|
2700
|
-
foundRoute = route
|
|
2701
|
-
routeParams = matchedParams
|
|
2702
|
-
break
|
|
2703
|
-
}
|
|
2704
|
-
}
|
|
2705
|
-
}
|
|
2706
|
-
// did not find a perfect fit, so take the fuzzy matching route if it exists
|
|
2707
|
-
if (!foundRoute && fuzzyMatch) {
|
|
2708
|
-
foundRoute = fuzzyMatch.foundRoute
|
|
2709
|
-
routeParams = fuzzyMatch.routeParams
|
|
2710
|
-
}
|
|
2638
|
+
let foundRoute: TRouteLike | undefined = undefined
|
|
2639
|
+
const match = findRouteMatch<TRouteLike>(trimmedPath, processedTree, true)
|
|
2640
|
+
if (match) {
|
|
2641
|
+
foundRoute = match.route
|
|
2642
|
+
Object.assign(routeParams, match.params) // Copy params, because they're cached
|
|
2711
2643
|
}
|
|
2712
2644
|
|
|
2713
2645
|
let routeCursor: TRouteLike = foundRoute || routesById[rootRouteId]!
|
package/src/ssr/constants.ts
CHANGED
package/src/ssr/ssr-client.ts
CHANGED
|
@@ -6,11 +6,12 @@ import type { AnyRouter } from '../router'
|
|
|
6
6
|
import type { Manifest } from '../manifest'
|
|
7
7
|
import type { RouteContextOptions } from '../route'
|
|
8
8
|
import type { AnySerializationAdapter } from './serializer/transformer'
|
|
9
|
-
import type { GLOBAL_TSR } from './constants'
|
|
9
|
+
import type { GLOBAL_SEROVAL, GLOBAL_TSR } from './constants'
|
|
10
10
|
|
|
11
11
|
declare global {
|
|
12
12
|
interface Window {
|
|
13
13
|
[GLOBAL_TSR]?: TsrSsrGlobal
|
|
14
|
+
[GLOBAL_SEROVAL]?: any
|
|
14
15
|
}
|
|
15
16
|
}
|
|
16
17
|
|
|
@@ -25,6 +26,10 @@ export interface TsrSsrGlobal {
|
|
|
25
26
|
t?: Map<string, (value: any) => any>
|
|
26
27
|
// this flag indicates whether the transformers were initialized
|
|
27
28
|
initialized?: boolean
|
|
29
|
+
// router is hydrated and doesnt need the streamed values anymore
|
|
30
|
+
hydrated?: boolean
|
|
31
|
+
// stream has ended
|
|
32
|
+
streamEnd?: boolean
|
|
28
33
|
}
|
|
29
34
|
|
|
30
35
|
function hydrateMatch(
|
|
@@ -165,6 +170,10 @@ export async function hydrate(router: AnyRouter): Promise<any> {
|
|
|
165
170
|
// Allow the user to handle custom hydration data
|
|
166
171
|
await router.options.hydrate?.(dehydratedData)
|
|
167
172
|
|
|
173
|
+
window.$_TSR.hydrated = true
|
|
174
|
+
// potentially clean up streamed values IF stream has ended already
|
|
175
|
+
window.$_TSR.c()
|
|
176
|
+
|
|
168
177
|
// now that all necessary data is hydrated:
|
|
169
178
|
// 1) fully reconstruct the route context
|
|
170
179
|
// 2) execute `head()` and `scripts()` for each match
|
package/src/ssr/ssr-server.ts
CHANGED
|
@@ -48,6 +48,54 @@ export function dehydrateMatch(match: AnyRouteMatch): DehydratedMatch {
|
|
|
48
48
|
return dehydratedMatch
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
const INITIAL_SCRIPTS = [
|
|
52
|
+
getCrossReferenceHeader(SCOPE_ID),
|
|
53
|
+
minifiedTsrBootStrapScript,
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
class ScriptBuffer {
|
|
57
|
+
constructor(private router: AnyRouter) {}
|
|
58
|
+
private _queue: Array<string> = [...INITIAL_SCRIPTS]
|
|
59
|
+
private _scriptBarrierLifted = false
|
|
60
|
+
|
|
61
|
+
enqueue(script: string) {
|
|
62
|
+
if (this._scriptBarrierLifted && this._queue.length === 0) {
|
|
63
|
+
queueMicrotask(() => {
|
|
64
|
+
this.injectBufferedScripts()
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
this._queue.push(script)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
liftBarrier() {
|
|
71
|
+
if (this._scriptBarrierLifted) return
|
|
72
|
+
this._scriptBarrierLifted = true
|
|
73
|
+
if (this._queue.length > 0) {
|
|
74
|
+
queueMicrotask(() => {
|
|
75
|
+
this.injectBufferedScripts()
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
takeAll() {
|
|
81
|
+
const bufferedScripts = this._queue
|
|
82
|
+
this._queue = []
|
|
83
|
+
if (bufferedScripts.length === 0) {
|
|
84
|
+
return undefined
|
|
85
|
+
}
|
|
86
|
+
bufferedScripts.push(`${GLOBAL_TSR}.c()`)
|
|
87
|
+
const joinedScripts = bufferedScripts.join(';')
|
|
88
|
+
return joinedScripts
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
injectBufferedScripts() {
|
|
92
|
+
const scriptsToInject = this.takeAll()
|
|
93
|
+
if (scriptsToInject) {
|
|
94
|
+
this.router.serverSsr!.injectScript(() => scriptsToInject)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
51
99
|
export function attachRouterServerSsrUtils({
|
|
52
100
|
router,
|
|
53
101
|
manifest,
|
|
@@ -58,16 +106,9 @@ export function attachRouterServerSsrUtils({
|
|
|
58
106
|
router.ssr = {
|
|
59
107
|
manifest,
|
|
60
108
|
}
|
|
61
|
-
let initialScriptSent = false
|
|
62
|
-
const getInitialScript = () => {
|
|
63
|
-
if (initialScriptSent) {
|
|
64
|
-
return ''
|
|
65
|
-
}
|
|
66
|
-
initialScriptSent = true
|
|
67
|
-
return `${getCrossReferenceHeader(SCOPE_ID)};${minifiedTsrBootStrapScript};`
|
|
68
|
-
}
|
|
69
109
|
let _dehydrated = false
|
|
70
110
|
const listeners: Array<() => void> = []
|
|
111
|
+
const scriptBuffer = new ScriptBuffer(router)
|
|
71
112
|
|
|
72
113
|
router.serverSsr = {
|
|
73
114
|
injectedHtml: [],
|
|
@@ -84,7 +125,10 @@ export function attachRouterServerSsrUtils({
|
|
|
84
125
|
injectScript: (getScript) => {
|
|
85
126
|
return router.serverSsr!.injectHtml(async () => {
|
|
86
127
|
const script = await getScript()
|
|
87
|
-
|
|
128
|
+
if (!script) {
|
|
129
|
+
return ''
|
|
130
|
+
}
|
|
131
|
+
return `<script${router.options.ssr?.nonce ? `nonce='${router.options.ssr.nonce}' ` : ''} class='$tsr'>${script}</script>`
|
|
88
132
|
})
|
|
89
133
|
},
|
|
90
134
|
dehydrate: async () => {
|
|
@@ -104,7 +148,10 @@ export function attachRouterServerSsrUtils({
|
|
|
104
148
|
if (lastMatchId) {
|
|
105
149
|
dehydratedRouter.lastMatchId = lastMatchId
|
|
106
150
|
}
|
|
107
|
-
|
|
151
|
+
const dehydratedData = await router.options.dehydrate?.()
|
|
152
|
+
if (dehydratedData) {
|
|
153
|
+
dehydratedRouter.dehydratedData = dehydratedData
|
|
154
|
+
}
|
|
108
155
|
_dehydrated = true
|
|
109
156
|
|
|
110
157
|
const p = createControlledPromise<string>()
|
|
@@ -115,6 +162,7 @@ export function attachRouterServerSsrUtils({
|
|
|
115
162
|
| Array<AnySerializationAdapter>
|
|
116
163
|
| undefined
|
|
117
164
|
)?.map((t) => makeSsrSerovalPlugin(t, trackPlugins)) ?? []
|
|
165
|
+
|
|
118
166
|
crossSerializeStream(dehydratedRouter, {
|
|
119
167
|
refs: new Map(),
|
|
120
168
|
plugins: [...plugins, ...defaultSerovalPlugins],
|
|
@@ -123,10 +171,13 @@ export function attachRouterServerSsrUtils({
|
|
|
123
171
|
if (trackPlugins.didRun) {
|
|
124
172
|
serialized = GLOBAL_TSR + '.p(()=>' + serialized + ')'
|
|
125
173
|
}
|
|
126
|
-
|
|
174
|
+
scriptBuffer.enqueue(serialized)
|
|
127
175
|
},
|
|
128
176
|
scopeId: SCOPE_ID,
|
|
129
|
-
onDone: () =>
|
|
177
|
+
onDone: () => {
|
|
178
|
+
scriptBuffer.enqueue(GLOBAL_TSR + '.streamEnd=true')
|
|
179
|
+
p.resolve('')
|
|
180
|
+
},
|
|
130
181
|
onError: (err) => p.reject(err),
|
|
131
182
|
})
|
|
132
183
|
// make sure the stream is kept open until the promise is resolved
|
|
@@ -138,6 +189,12 @@ export function attachRouterServerSsrUtils({
|
|
|
138
189
|
onRenderFinished: (listener) => listeners.push(listener),
|
|
139
190
|
setRenderFinished: () => {
|
|
140
191
|
listeners.forEach((l) => l())
|
|
192
|
+
scriptBuffer.liftBarrier()
|
|
193
|
+
},
|
|
194
|
+
takeBufferedScripts() {
|
|
195
|
+
const scripts = scriptBuffer.takeAll()
|
|
196
|
+
scriptBuffer.liftBarrier()
|
|
197
|
+
return scripts
|
|
141
198
|
},
|
|
142
199
|
}
|
|
143
200
|
}
|
package/src/ssr/tsrScript.ts
CHANGED
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
const invariant = require("tiny-invariant");
|
|
4
|
-
const path = require("./path.cjs");
|
|
5
|
-
const SLASH_SCORE = 0.75;
|
|
6
|
-
const STATIC_SEGMENT_SCORE = 1;
|
|
7
|
-
const REQUIRED_PARAM_BASE_SCORE = 0.5;
|
|
8
|
-
const OPTIONAL_PARAM_BASE_SCORE = 0.4;
|
|
9
|
-
const WILDCARD_PARAM_BASE_SCORE = 0.25;
|
|
10
|
-
const STATIC_AFTER_DYNAMIC_BONUS_SCORE = 0.2;
|
|
11
|
-
const BOTH_PRESENCE_BASE_SCORE = 0.05;
|
|
12
|
-
const PREFIX_PRESENCE_BASE_SCORE = 0.02;
|
|
13
|
-
const SUFFIX_PRESENCE_BASE_SCORE = 0.01;
|
|
14
|
-
const PREFIX_LENGTH_SCORE_MULTIPLIER = 2e-4;
|
|
15
|
-
const SUFFIX_LENGTH_SCORE_MULTIPLIER = 1e-4;
|
|
16
|
-
function handleParam(segment, baseScore) {
|
|
17
|
-
if (segment.prefixSegment && segment.suffixSegment) {
|
|
18
|
-
return baseScore + BOTH_PRESENCE_BASE_SCORE + PREFIX_LENGTH_SCORE_MULTIPLIER * segment.prefixSegment.length + SUFFIX_LENGTH_SCORE_MULTIPLIER * segment.suffixSegment.length;
|
|
19
|
-
}
|
|
20
|
-
if (segment.prefixSegment) {
|
|
21
|
-
return baseScore + PREFIX_PRESENCE_BASE_SCORE + PREFIX_LENGTH_SCORE_MULTIPLIER * segment.prefixSegment.length;
|
|
22
|
-
}
|
|
23
|
-
if (segment.suffixSegment) {
|
|
24
|
-
return baseScore + SUFFIX_PRESENCE_BASE_SCORE + SUFFIX_LENGTH_SCORE_MULTIPLIER * segment.suffixSegment.length;
|
|
25
|
-
}
|
|
26
|
-
return baseScore;
|
|
27
|
-
}
|
|
28
|
-
function sortRoutes(routes) {
|
|
29
|
-
const scoredRoutes = [];
|
|
30
|
-
routes.forEach((d, i) => {
|
|
31
|
-
if (d.isRoot || !d.path) {
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
const trimmed = path.trimPathLeft(d.fullPath);
|
|
35
|
-
let parsed = path.parsePathname(trimmed);
|
|
36
|
-
let skip = 0;
|
|
37
|
-
while (parsed.length > skip + 1 && parsed[skip]?.value === "/") {
|
|
38
|
-
skip++;
|
|
39
|
-
}
|
|
40
|
-
if (skip > 0) parsed = parsed.slice(skip);
|
|
41
|
-
let optionalParamCount = 0;
|
|
42
|
-
let hasStaticAfter = false;
|
|
43
|
-
const scores = parsed.map((segment, index) => {
|
|
44
|
-
if (segment.value === "/") {
|
|
45
|
-
return SLASH_SCORE;
|
|
46
|
-
}
|
|
47
|
-
if (segment.type === path.SEGMENT_TYPE_PATHNAME) {
|
|
48
|
-
return STATIC_SEGMENT_SCORE;
|
|
49
|
-
}
|
|
50
|
-
let baseScore = void 0;
|
|
51
|
-
if (segment.type === path.SEGMENT_TYPE_PARAM) {
|
|
52
|
-
baseScore = REQUIRED_PARAM_BASE_SCORE;
|
|
53
|
-
} else if (segment.type === path.SEGMENT_TYPE_OPTIONAL_PARAM) {
|
|
54
|
-
baseScore = OPTIONAL_PARAM_BASE_SCORE;
|
|
55
|
-
optionalParamCount++;
|
|
56
|
-
} else {
|
|
57
|
-
baseScore = WILDCARD_PARAM_BASE_SCORE;
|
|
58
|
-
}
|
|
59
|
-
for (let i2 = index + 1; i2 < parsed.length; i2++) {
|
|
60
|
-
const nextSegment = parsed[i2];
|
|
61
|
-
if (nextSegment.type === path.SEGMENT_TYPE_PATHNAME && nextSegment.value !== "/") {
|
|
62
|
-
hasStaticAfter = true;
|
|
63
|
-
return handleParam(
|
|
64
|
-
segment,
|
|
65
|
-
baseScore + STATIC_AFTER_DYNAMIC_BONUS_SCORE
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
return handleParam(segment, baseScore);
|
|
70
|
-
});
|
|
71
|
-
scoredRoutes.push({
|
|
72
|
-
child: d,
|
|
73
|
-
trimmed,
|
|
74
|
-
parsed,
|
|
75
|
-
index: i,
|
|
76
|
-
scores,
|
|
77
|
-
optionalParamCount,
|
|
78
|
-
hasStaticAfter
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
const flatRoutes = scoredRoutes.sort((a, b) => {
|
|
82
|
-
const minLength = Math.min(a.scores.length, b.scores.length);
|
|
83
|
-
for (let i = 0; i < minLength; i++) {
|
|
84
|
-
if (a.scores[i] !== b.scores[i]) {
|
|
85
|
-
return b.scores[i] - a.scores[i];
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
if (a.scores.length !== b.scores.length) {
|
|
89
|
-
if (a.optionalParamCount !== b.optionalParamCount) {
|
|
90
|
-
if (a.hasStaticAfter === b.hasStaticAfter) {
|
|
91
|
-
return a.optionalParamCount - b.optionalParamCount;
|
|
92
|
-
} else if (a.hasStaticAfter && !b.hasStaticAfter) {
|
|
93
|
-
return -1;
|
|
94
|
-
} else if (!a.hasStaticAfter && b.hasStaticAfter) {
|
|
95
|
-
return 1;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
return b.scores.length - a.scores.length;
|
|
99
|
-
}
|
|
100
|
-
for (let i = 0; i < minLength; i++) {
|
|
101
|
-
if (a.parsed[i].value !== b.parsed[i].value) {
|
|
102
|
-
return a.parsed[i].value > b.parsed[i].value ? 1 : -1;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
return a.index - b.index;
|
|
106
|
-
}).map((d, i) => {
|
|
107
|
-
d.child.rank = i;
|
|
108
|
-
return d.child;
|
|
109
|
-
});
|
|
110
|
-
return flatRoutes;
|
|
111
|
-
}
|
|
112
|
-
function processRouteTree({
|
|
113
|
-
routeTree,
|
|
114
|
-
initRoute
|
|
115
|
-
}) {
|
|
116
|
-
const routesById = {};
|
|
117
|
-
const routesByPath = {};
|
|
118
|
-
const recurseRoutes = (childRoutes) => {
|
|
119
|
-
childRoutes.forEach((childRoute, i) => {
|
|
120
|
-
initRoute?.(childRoute, i);
|
|
121
|
-
const existingRoute = routesById[childRoute.id];
|
|
122
|
-
invariant(
|
|
123
|
-
!existingRoute,
|
|
124
|
-
`Duplicate routes found with id: ${String(childRoute.id)}`
|
|
125
|
-
);
|
|
126
|
-
routesById[childRoute.id] = childRoute;
|
|
127
|
-
if (!childRoute.isRoot && childRoute.path) {
|
|
128
|
-
const trimmedFullPath = path.trimPathRight(childRoute.fullPath);
|
|
129
|
-
if (!routesByPath[trimmedFullPath] || childRoute.fullPath.endsWith("/")) {
|
|
130
|
-
routesByPath[trimmedFullPath] = childRoute;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
const children = childRoute.children;
|
|
134
|
-
if (children?.length) {
|
|
135
|
-
recurseRoutes(children);
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
};
|
|
139
|
-
recurseRoutes([routeTree]);
|
|
140
|
-
const flatRoutes = sortRoutes(Object.values(routesById));
|
|
141
|
-
return { routesById, routesByPath, flatRoutes };
|
|
142
|
-
}
|
|
143
|
-
exports.processRouteTree = processRouteTree;
|
|
144
|
-
//# sourceMappingURL=process-route-tree.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"process-route-tree.cjs","sources":["../../src/process-route-tree.ts"],"sourcesContent":["import invariant from 'tiny-invariant'\nimport {\n SEGMENT_TYPE_OPTIONAL_PARAM,\n SEGMENT_TYPE_PARAM,\n SEGMENT_TYPE_PATHNAME,\n parsePathname,\n trimPathLeft,\n trimPathRight,\n} from './path'\nimport type { Segment } from './path'\nimport type { RouteLike } from './route'\n\nconst SLASH_SCORE = 0.75\nconst STATIC_SEGMENT_SCORE = 1\nconst REQUIRED_PARAM_BASE_SCORE = 0.5\nconst OPTIONAL_PARAM_BASE_SCORE = 0.4\nconst WILDCARD_PARAM_BASE_SCORE = 0.25\nconst STATIC_AFTER_DYNAMIC_BONUS_SCORE = 0.2\nconst BOTH_PRESENCE_BASE_SCORE = 0.05\nconst PREFIX_PRESENCE_BASE_SCORE = 0.02\nconst SUFFIX_PRESENCE_BASE_SCORE = 0.01\nconst PREFIX_LENGTH_SCORE_MULTIPLIER = 0.0002\nconst SUFFIX_LENGTH_SCORE_MULTIPLIER = 0.0001\n\nfunction handleParam(segment: Segment, baseScore: number) {\n if (segment.prefixSegment && segment.suffixSegment) {\n return (\n baseScore +\n BOTH_PRESENCE_BASE_SCORE +\n PREFIX_LENGTH_SCORE_MULTIPLIER * segment.prefixSegment.length +\n SUFFIX_LENGTH_SCORE_MULTIPLIER * segment.suffixSegment.length\n )\n }\n\n if (segment.prefixSegment) {\n return (\n baseScore +\n PREFIX_PRESENCE_BASE_SCORE +\n PREFIX_LENGTH_SCORE_MULTIPLIER * segment.prefixSegment.length\n )\n }\n\n if (segment.suffixSegment) {\n return (\n baseScore +\n SUFFIX_PRESENCE_BASE_SCORE +\n SUFFIX_LENGTH_SCORE_MULTIPLIER * segment.suffixSegment.length\n )\n }\n\n return baseScore\n}\n\nfunction sortRoutes<TRouteLike extends RouteLike>(\n routes: ReadonlyArray<TRouteLike>,\n): Array<TRouteLike> {\n const scoredRoutes: Array<{\n child: TRouteLike\n trimmed: string\n parsed: ReadonlyArray<Segment>\n index: number\n scores: Array<number>\n hasStaticAfter: boolean\n optionalParamCount: number\n }> = []\n\n routes.forEach((d, i) => {\n if (d.isRoot || !d.path) {\n return\n }\n\n const trimmed = trimPathLeft(d.fullPath)\n let parsed = parsePathname(trimmed)\n\n // Removes the leading slash if it is not the only remaining segment\n let skip = 0\n while (parsed.length > skip + 1 && parsed[skip]?.value === '/') {\n skip++\n }\n if (skip > 0) parsed = parsed.slice(skip)\n\n let optionalParamCount = 0\n let hasStaticAfter = false\n const scores = parsed.map((segment, index) => {\n if (segment.value === '/') {\n return SLASH_SCORE\n }\n\n if (segment.type === SEGMENT_TYPE_PATHNAME) {\n return STATIC_SEGMENT_SCORE\n }\n\n let baseScore: number | undefined = undefined\n if (segment.type === SEGMENT_TYPE_PARAM) {\n baseScore = REQUIRED_PARAM_BASE_SCORE\n } else if (segment.type === SEGMENT_TYPE_OPTIONAL_PARAM) {\n baseScore = OPTIONAL_PARAM_BASE_SCORE\n optionalParamCount++\n } else {\n baseScore = WILDCARD_PARAM_BASE_SCORE\n }\n\n // if there is any static segment (that is not an index) after a required / optional param,\n // we will boost this param so it ranks higher than a required/optional param without a static segment after it\n // JUST FOR SORTING, NOT FOR MATCHING\n for (let i = index + 1; i < parsed.length; i++) {\n const nextSegment = parsed[i]!\n if (\n nextSegment.type === SEGMENT_TYPE_PATHNAME &&\n nextSegment.value !== '/'\n ) {\n hasStaticAfter = true\n return handleParam(\n segment,\n baseScore + STATIC_AFTER_DYNAMIC_BONUS_SCORE,\n )\n }\n }\n\n return handleParam(segment, baseScore)\n })\n\n scoredRoutes.push({\n child: d,\n trimmed,\n parsed,\n index: i,\n scores,\n optionalParamCount,\n hasStaticAfter,\n })\n })\n\n const flatRoutes = scoredRoutes\n .sort((a, b) => {\n const minLength = Math.min(a.scores.length, b.scores.length)\n\n // Sort by segment-by-segment score comparison ONLY for the common prefix\n for (let i = 0; i < minLength; i++) {\n if (a.scores[i] !== b.scores[i]) {\n return b.scores[i]! - a.scores[i]!\n }\n }\n\n // If all common segments have equal scores, then consider length and specificity\n if (a.scores.length !== b.scores.length) {\n // If different number of optional parameters, fewer optional parameters wins (more specific)\n // only if both or none of the routes has static segments after the params\n if (a.optionalParamCount !== b.optionalParamCount) {\n if (a.hasStaticAfter === b.hasStaticAfter) {\n return a.optionalParamCount - b.optionalParamCount\n } else if (a.hasStaticAfter && !b.hasStaticAfter) {\n return -1\n } else if (!a.hasStaticAfter && b.hasStaticAfter) {\n return 1\n }\n }\n\n // If same number of optional parameters, longer path wins (for static segments)\n return b.scores.length - a.scores.length\n }\n\n // Sort by min available parsed value for alphabetical ordering\n for (let i = 0; i < minLength; i++) {\n if (a.parsed[i]!.value !== b.parsed[i]!.value) {\n return a.parsed[i]!.value > b.parsed[i]!.value ? 1 : -1\n }\n }\n\n // Sort by original index\n return a.index - b.index\n })\n .map((d, i) => {\n d.child.rank = i\n return d.child\n })\n\n return flatRoutes\n}\n\nexport type ProcessRouteTreeResult<TRouteLike extends RouteLike> = {\n routesById: Record<string, TRouteLike>\n routesByPath: Record<string, TRouteLike>\n flatRoutes: Array<TRouteLike>\n}\n\n/**\n * Build lookup maps and a specificity-sorted flat list from a route tree.\n * Returns `routesById`, `routesByPath`, and `flatRoutes`.\n */\n/**\n * Build lookup maps and a specificity-sorted flat list from a route tree.\n * Returns `routesById`, `routesByPath`, and `flatRoutes`.\n */\nexport function processRouteTree<TRouteLike extends RouteLike>({\n routeTree,\n initRoute,\n}: {\n routeTree: TRouteLike\n initRoute?: (route: TRouteLike, index: number) => void\n}): ProcessRouteTreeResult<TRouteLike> {\n const routesById = {} as Record<string, TRouteLike>\n const routesByPath = {} as Record<string, TRouteLike>\n\n const recurseRoutes = (childRoutes: Array<TRouteLike>) => {\n childRoutes.forEach((childRoute, i) => {\n initRoute?.(childRoute, i)\n\n const existingRoute = routesById[childRoute.id]\n\n invariant(\n !existingRoute,\n `Duplicate routes found with id: ${String(childRoute.id)}`,\n )\n\n routesById[childRoute.id] = childRoute\n\n if (!childRoute.isRoot && childRoute.path) {\n const trimmedFullPath = trimPathRight(childRoute.fullPath)\n if (\n !routesByPath[trimmedFullPath] ||\n childRoute.fullPath.endsWith('/')\n ) {\n routesByPath[trimmedFullPath] = childRoute\n }\n }\n\n const children = childRoute.children as Array<TRouteLike>\n\n if (children?.length) {\n recurseRoutes(children)\n }\n })\n }\n\n recurseRoutes([routeTree])\n\n const flatRoutes = sortRoutes(Object.values(routesById))\n\n return { routesById, routesByPath, flatRoutes }\n}\n"],"names":["trimPathLeft","parsePathname","SEGMENT_TYPE_PATHNAME","SEGMENT_TYPE_PARAM","SEGMENT_TYPE_OPTIONAL_PARAM","i","trimPathRight"],"mappings":"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"}
|