@tanstack/router-core 1.125.4 → 1.127.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/Matches.cjs.map +1 -1
- package/dist/cjs/Matches.d.cts +1 -1
- package/dist/cjs/RouterProvider.d.cts +1 -0
- package/dist/cjs/index.d.cts +1 -2
- package/dist/cjs/router.cjs +26 -33
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/router.d.cts +10 -57
- package/dist/cjs/ssr/client.cjs +0 -2
- package/dist/cjs/ssr/client.cjs.map +1 -1
- package/dist/cjs/ssr/client.d.cts +1 -2
- package/dist/cjs/ssr/createRequestHandler.cjs +2 -1
- package/dist/cjs/ssr/createRequestHandler.cjs.map +1 -1
- 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 +0 -4
- package/dist/cjs/ssr/server.cjs.map +1 -1
- package/dist/cjs/ssr/server.d.cts +1 -3
- package/dist/cjs/ssr/ssr-client.cjs +18 -56
- package/dist/cjs/ssr/ssr-client.cjs.map +1 -1
- package/dist/cjs/ssr/ssr-client.d.cts +17 -57
- package/dist/cjs/ssr/ssr-server.cjs +75 -220
- package/dist/cjs/ssr/ssr-server.cjs.map +1 -1
- package/dist/cjs/ssr/ssr-server.d.cts +14 -28
- package/dist/cjs/ssr/transformStreamWithRouter.cjs +1 -0
- package/dist/cjs/ssr/transformStreamWithRouter.cjs.map +1 -1
- package/dist/cjs/ssr/tsrScript.cjs +1 -1
- package/dist/cjs/ssr/tsrScript.cjs.map +1 -1
- package/dist/cjs/ssr/tsrScript.d.cts +0 -1
- package/dist/esm/Matches.d.ts +1 -1
- package/dist/esm/Matches.js.map +1 -1
- package/dist/esm/RouterProvider.d.ts +1 -0
- package/dist/esm/index.d.ts +1 -2
- package/dist/esm/router.d.ts +10 -57
- package/dist/esm/router.js +26 -33
- package/dist/esm/router.js.map +1 -1
- package/dist/esm/ssr/client.d.ts +1 -2
- package/dist/esm/ssr/client.js +1 -3
- package/dist/esm/ssr/client.js.map +1 -1
- package/dist/esm/ssr/createRequestHandler.js +3 -2
- package/dist/esm/ssr/createRequestHandler.js.map +1 -1
- 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 +1 -3
- package/dist/esm/ssr/server.js +1 -5
- package/dist/esm/ssr/ssr-client.d.ts +17 -57
- package/dist/esm/ssr/ssr-client.js +18 -56
- package/dist/esm/ssr/ssr-client.js.map +1 -1
- package/dist/esm/ssr/ssr-server.d.ts +14 -28
- package/dist/esm/ssr/ssr-server.js +76 -221
- package/dist/esm/ssr/ssr-server.js.map +1 -1
- package/dist/esm/ssr/transformStreamWithRouter.js +1 -0
- package/dist/esm/ssr/transformStreamWithRouter.js.map +1 -1
- package/dist/esm/ssr/tsrScript.d.ts +0 -1
- package/dist/esm/ssr/tsrScript.js +1 -1
- package/dist/esm/ssr/tsrScript.js.map +1 -1
- package/package.json +3 -1
- package/src/Matches.ts +1 -1
- package/src/RouterProvider.ts +1 -0
- package/src/index.ts +0 -18
- package/src/router.ts +41 -89
- package/src/ssr/client.ts +1 -11
- package/src/ssr/createRequestHandler.ts +2 -2
- package/src/ssr/seroval-plugins.ts +43 -0
- package/src/ssr/server.ts +1 -14
- package/src/ssr/ssr-client.ts +35 -128
- package/src/ssr/ssr-server.ts +89 -307
- package/src/ssr/transformStreamWithRouter.ts +1 -0
- package/src/ssr/tsrScript.ts +4 -88
- package/dist/cjs/serializer.cjs +0 -146
- package/dist/cjs/serializer.cjs.map +0 -1
- package/dist/cjs/serializer.d.cts +0 -28
- package/dist/esm/serializer.d.ts +0 -28
- package/dist/esm/serializer.js +0 -146
- package/dist/esm/serializer.js.map +0 -1
- package/src/serializer.ts +0 -205
package/src/router.ts
CHANGED
|
@@ -46,7 +46,6 @@ import type {
|
|
|
46
46
|
Updater,
|
|
47
47
|
} from './utils'
|
|
48
48
|
import type { ParsedLocation } from './location'
|
|
49
|
-
import type { DeferredPromiseState } from './defer'
|
|
50
49
|
import type {
|
|
51
50
|
AnyContext,
|
|
52
51
|
AnyRoute,
|
|
@@ -78,7 +77,6 @@ import type {
|
|
|
78
77
|
NavigateFn,
|
|
79
78
|
} from './RouterProvider'
|
|
80
79
|
import type { Manifest } from './manifest'
|
|
81
|
-
import type { TsrSerializer } from './serializer'
|
|
82
80
|
import type { AnySchema, AnyValidator } from './validators'
|
|
83
81
|
import type { NavigateOptions, ResolveRelativePath, ToOptions } from './link'
|
|
84
82
|
import type { NotFoundError } from './not-found'
|
|
@@ -288,7 +286,7 @@ export interface RouterOptions<
|
|
|
288
286
|
* @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#dehydrate-method)
|
|
289
287
|
* @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/external-data-loading#critical-dehydrationhydration)
|
|
290
288
|
*/
|
|
291
|
-
dehydrate?: () => TDehydrated
|
|
289
|
+
dehydrate?: () => Awaitable<TDehydrated>
|
|
292
290
|
/**
|
|
293
291
|
* A function that will be called when the router is hydrated.
|
|
294
292
|
*
|
|
@@ -441,6 +439,7 @@ export interface BuildNextOptions {
|
|
|
441
439
|
href?: string
|
|
442
440
|
_fromLocation?: ParsedLocation
|
|
443
441
|
unsafeRelative?: 'path'
|
|
442
|
+
_isNavigate?: boolean
|
|
444
443
|
}
|
|
445
444
|
|
|
446
445
|
type NavigationEventInfo = {
|
|
@@ -451,7 +450,7 @@ type NavigationEventInfo = {
|
|
|
451
450
|
hashChanged: boolean
|
|
452
451
|
}
|
|
453
452
|
|
|
454
|
-
export
|
|
453
|
+
export interface RouterEvents {
|
|
455
454
|
onBeforeNavigate: {
|
|
456
455
|
type: 'onBeforeNavigate'
|
|
457
456
|
} & NavigationEventInfo
|
|
@@ -467,10 +466,6 @@ export type RouterEvents = {
|
|
|
467
466
|
onBeforeRouteMount: {
|
|
468
467
|
type: 'onBeforeRouteMount'
|
|
469
468
|
} & NavigationEventInfo
|
|
470
|
-
onInjectedHtml: {
|
|
471
|
-
type: 'onInjectedHtml'
|
|
472
|
-
promise: Promise<string>
|
|
473
|
-
}
|
|
474
469
|
onRendered: {
|
|
475
470
|
type: 'onRendered'
|
|
476
471
|
} & NavigationEventInfo
|
|
@@ -485,6 +480,11 @@ export type RouterListener<TRouterEvent extends RouterEvent> = {
|
|
|
485
480
|
fn: ListenerFn<TRouterEvent>
|
|
486
481
|
}
|
|
487
482
|
|
|
483
|
+
export type SubscribeFn = <TType extends keyof RouterEvents>(
|
|
484
|
+
eventType: TType,
|
|
485
|
+
fn: ListenerFn<RouterEvents[TType]>,
|
|
486
|
+
) => () => void
|
|
487
|
+
|
|
488
488
|
export interface MatchRoutesOpts {
|
|
489
489
|
preload?: boolean
|
|
490
490
|
throwOnError?: boolean
|
|
@@ -522,11 +522,6 @@ export type RouterConstructorOptions<
|
|
|
522
522
|
> &
|
|
523
523
|
RouterContextOptions<TRouteTree>
|
|
524
524
|
|
|
525
|
-
export interface RouterErrorSerializer<TSerializedError> {
|
|
526
|
-
serialize: (err: unknown) => TSerializedError
|
|
527
|
-
deserialize: (err: TSerializedError) => unknown
|
|
528
|
-
}
|
|
529
|
-
|
|
530
525
|
export type PreloadRouteFn<
|
|
531
526
|
TRouteTree extends AnyRoute,
|
|
532
527
|
TTrailingSlashOption extends TrailingSlashOption,
|
|
@@ -623,11 +618,6 @@ export type CommitLocationFn = ({
|
|
|
623
618
|
|
|
624
619
|
export type StartTransitionFn = (fn: () => void) => void
|
|
625
620
|
|
|
626
|
-
export type SubscribeFn = <TType extends keyof RouterEvents>(
|
|
627
|
-
eventType: TType,
|
|
628
|
-
fn: ListenerFn<RouterEvents[TType]>,
|
|
629
|
-
) => () => void
|
|
630
|
-
|
|
631
621
|
export interface MatchRoutesFn {
|
|
632
622
|
(
|
|
633
623
|
pathname: string,
|
|
@@ -657,16 +647,16 @@ export type ClearCacheFn<TRouter extends AnyRouter> = (opts?: {
|
|
|
657
647
|
filter?: (d: MakeRouteMatchUnion<TRouter>) => boolean
|
|
658
648
|
}) => void
|
|
659
649
|
|
|
660
|
-
export interface
|
|
650
|
+
export interface ServerSsr {
|
|
661
651
|
injectedHtml: Array<InjectedHtmlEntry>
|
|
662
652
|
injectHtml: (getHtml: () => string | Promise<string>) => Promise<void>
|
|
663
653
|
injectScript: (
|
|
664
654
|
getScript: () => string | Promise<string>,
|
|
665
655
|
opts?: { logScript?: boolean },
|
|
666
656
|
) => Promise<void>
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
657
|
+
isDehydrated: () => boolean
|
|
658
|
+
onRenderFinished: (listener: () => void) => void
|
|
659
|
+
dehydrate: () => Promise<void>
|
|
670
660
|
}
|
|
671
661
|
|
|
672
662
|
export type AnyRouterWithContext<TContext> = RouterCore<
|
|
@@ -709,29 +699,6 @@ export function defaultSerializeError(err: unknown) {
|
|
|
709
699
|
data: err,
|
|
710
700
|
}
|
|
711
701
|
}
|
|
712
|
-
export interface ExtractedBaseEntry {
|
|
713
|
-
dataType: '__beforeLoadContext' | 'loaderData'
|
|
714
|
-
type: string
|
|
715
|
-
path: Array<string>
|
|
716
|
-
id: number
|
|
717
|
-
matchIndex: number
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
export interface ExtractedStream extends ExtractedBaseEntry {
|
|
721
|
-
type: 'stream'
|
|
722
|
-
streamState: StreamState
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
export interface ExtractedPromise extends ExtractedBaseEntry {
|
|
726
|
-
type: 'promise'
|
|
727
|
-
promiseState: DeferredPromiseState<any>
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
export type ExtractedEntry = ExtractedStream | ExtractedPromise
|
|
731
|
-
|
|
732
|
-
export type StreamState = {
|
|
733
|
-
promises: Array<ControlledPromise<string | null>>
|
|
734
|
-
}
|
|
735
702
|
|
|
736
703
|
export type TrailingSlashOption = 'always' | 'never' | 'preserve'
|
|
737
704
|
|
|
@@ -837,7 +804,7 @@ export class RouterCore<
|
|
|
837
804
|
})
|
|
838
805
|
|
|
839
806
|
if (typeof document !== 'undefined') {
|
|
840
|
-
|
|
807
|
+
self.__TSR_ROUTER__ = this
|
|
841
808
|
}
|
|
842
809
|
}
|
|
843
810
|
|
|
@@ -1292,7 +1259,7 @@ export class RouterCore<
|
|
|
1292
1259
|
error: undefined,
|
|
1293
1260
|
paramsError: parseErrors[index],
|
|
1294
1261
|
__routeContext: {},
|
|
1295
|
-
__beforeLoadContext:
|
|
1262
|
+
__beforeLoadContext: undefined,
|
|
1296
1263
|
context: {},
|
|
1297
1264
|
abortController: new AbortController(),
|
|
1298
1265
|
fetchCount: 0,
|
|
@@ -1419,11 +1386,11 @@ export class RouterCore<
|
|
|
1419
1386
|
// We allow the caller to override the current location
|
|
1420
1387
|
const currentLocation = dest._fromLocation || this.latestLocation
|
|
1421
1388
|
|
|
1422
|
-
const
|
|
1389
|
+
const allCurrentLocationMatches = this.matchRoutes(currentLocation, {
|
|
1423
1390
|
_buildLocation: true,
|
|
1424
1391
|
})
|
|
1425
1392
|
|
|
1426
|
-
const lastMatch = last(
|
|
1393
|
+
const lastMatch = last(allCurrentLocationMatches)!
|
|
1427
1394
|
|
|
1428
1395
|
// First let's find the starting pathname
|
|
1429
1396
|
// By default, start with the current location
|
|
@@ -1442,12 +1409,29 @@ export class RouterCore<
|
|
|
1442
1409
|
fromPath = currentLocation.pathname
|
|
1443
1410
|
} else if (routeIsChanging && dest.from) {
|
|
1444
1411
|
fromPath = dest.from
|
|
1445
|
-
const existingFrom = [...allFromMatches].reverse().find((d) => {
|
|
1446
|
-
return this.comparePaths(d.fullPath, fromPath)
|
|
1447
|
-
})
|
|
1448
1412
|
|
|
1449
|
-
|
|
1450
|
-
|
|
1413
|
+
// do this check only on navigations during test or development
|
|
1414
|
+
if (process.env.NODE_ENV !== 'production' && dest._isNavigate) {
|
|
1415
|
+
const allFromMatches = this.getMatchedRoutes(
|
|
1416
|
+
dest.from,
|
|
1417
|
+
undefined,
|
|
1418
|
+
).matchedRoutes
|
|
1419
|
+
|
|
1420
|
+
const matchedFrom = [...allCurrentLocationMatches]
|
|
1421
|
+
.reverse()
|
|
1422
|
+
.find((d) => {
|
|
1423
|
+
return this.comparePaths(d.fullPath, fromPath)
|
|
1424
|
+
})
|
|
1425
|
+
|
|
1426
|
+
const matchedCurrent = [...allFromMatches].reverse().find((d) => {
|
|
1427
|
+
return this.comparePaths(d.fullPath, currentLocation.pathname)
|
|
1428
|
+
})
|
|
1429
|
+
|
|
1430
|
+
// for from to be invalid it shouldn't just be unmatched to currentLocation
|
|
1431
|
+
// but the currentLocation should also be unmatched to from
|
|
1432
|
+
if (!matchedFrom && !matchedCurrent) {
|
|
1433
|
+
console.warn(`Could not find match for from: ${fromPath}`)
|
|
1434
|
+
}
|
|
1451
1435
|
}
|
|
1452
1436
|
}
|
|
1453
1437
|
|
|
@@ -1777,6 +1761,7 @@ export class RouterCore<
|
|
|
1777
1761
|
...rest,
|
|
1778
1762
|
href,
|
|
1779
1763
|
to: to as string,
|
|
1764
|
+
_isNavigate: true,
|
|
1780
1765
|
})
|
|
1781
1766
|
}
|
|
1782
1767
|
|
|
@@ -2169,10 +2154,6 @@ export class RouterCore<
|
|
|
2169
2154
|
this._handleNotFound(matches, err, {
|
|
2170
2155
|
updateMatch,
|
|
2171
2156
|
})
|
|
2172
|
-
this.serverSsr?.onMatchSettled({
|
|
2173
|
-
router: this,
|
|
2174
|
-
match: this.getMatch(match.id)!,
|
|
2175
|
-
})
|
|
2176
2157
|
throw err
|
|
2177
2158
|
}
|
|
2178
2159
|
}
|
|
@@ -2430,8 +2411,7 @@ export class RouterCore<
|
|
|
2430
2411
|
}
|
|
2431
2412
|
|
|
2432
2413
|
const beforeLoadContext =
|
|
2433
|
-
|
|
2434
|
-
{}
|
|
2414
|
+
await route.options.beforeLoad?.(beforeLoadFnContext)
|
|
2435
2415
|
|
|
2436
2416
|
if (
|
|
2437
2417
|
isRedirect(beforeLoadContext) ||
|
|
@@ -2524,10 +2504,6 @@ export class RouterCore<
|
|
|
2524
2504
|
...prev,
|
|
2525
2505
|
...head,
|
|
2526
2506
|
}))
|
|
2527
|
-
this.serverSsr?.onMatchSettled({
|
|
2528
|
-
router: this,
|
|
2529
|
-
match: this.getMatch(matchId)!,
|
|
2530
|
-
})
|
|
2531
2507
|
return this.getMatch(matchId)!
|
|
2532
2508
|
} else {
|
|
2533
2509
|
await potentialPendingMinPromise()
|
|
@@ -2689,11 +2665,6 @@ export class RouterCore<
|
|
|
2689
2665
|
...head,
|
|
2690
2666
|
}))
|
|
2691
2667
|
}
|
|
2692
|
-
|
|
2693
|
-
this.serverSsr?.onMatchSettled({
|
|
2694
|
-
router: this,
|
|
2695
|
-
match: this.getMatch(matchId)!,
|
|
2696
|
-
})
|
|
2697
2668
|
} catch (err) {
|
|
2698
2669
|
const head = await executeHead()
|
|
2699
2670
|
|
|
@@ -2754,10 +2725,6 @@ export class RouterCore<
|
|
|
2754
2725
|
...prev,
|
|
2755
2726
|
...head,
|
|
2756
2727
|
}))
|
|
2757
|
-
this.serverSsr?.onMatchSettled({
|
|
2758
|
-
router: this,
|
|
2759
|
-
match: this.getMatch(matchId)!,
|
|
2760
|
-
})
|
|
2761
2728
|
}
|
|
2762
2729
|
}
|
|
2763
2730
|
if (!loaderIsRunningAsync) {
|
|
@@ -3057,24 +3024,9 @@ export class RouterCore<
|
|
|
3057
3024
|
|
|
3058
3025
|
ssr?: {
|
|
3059
3026
|
manifest: Manifest | undefined
|
|
3060
|
-
serializer: TsrSerializer
|
|
3061
|
-
}
|
|
3062
|
-
|
|
3063
|
-
serverSsr?: {
|
|
3064
|
-
injectedHtml: Array<InjectedHtmlEntry>
|
|
3065
|
-
injectHtml: (getHtml: () => string | Promise<string>) => Promise<void>
|
|
3066
|
-
injectScript: (
|
|
3067
|
-
getScript: () => string | Promise<string>,
|
|
3068
|
-
opts?: { logScript?: boolean },
|
|
3069
|
-
) => Promise<void>
|
|
3070
|
-
streamValue: (key: string, value: any) => void
|
|
3071
|
-
streamedKeys: Set<string>
|
|
3072
|
-
onMatchSettled: (opts: { router: AnyRouter; match: AnyRouteMatch }) => any
|
|
3073
3027
|
}
|
|
3074
3028
|
|
|
3075
|
-
|
|
3076
|
-
getStreamedValue: <T>(key: string) => T | undefined
|
|
3077
|
-
}
|
|
3029
|
+
serverSsr?: ServerSsr
|
|
3078
3030
|
|
|
3079
3031
|
_handleNotFound = (
|
|
3080
3032
|
matches: Array<AnyRouteMatch>,
|
package/src/ssr/client.ts
CHANGED
|
@@ -2,14 +2,4 @@ export { mergeHeaders, headersInitToObject } from './headers'
|
|
|
2
2
|
export { json } from './json'
|
|
3
3
|
export type { JsonResponse } from './json'
|
|
4
4
|
export { hydrate } from './ssr-client'
|
|
5
|
-
export
|
|
6
|
-
DehydratedRouter,
|
|
7
|
-
ClientExtractedBaseEntry,
|
|
8
|
-
TsrSsrGlobal,
|
|
9
|
-
ClientExtractedEntry,
|
|
10
|
-
SsrMatch,
|
|
11
|
-
ClientExtractedPromise,
|
|
12
|
-
ClientExtractedStream,
|
|
13
|
-
ResolvePromiseState,
|
|
14
|
-
} from './ssr-client'
|
|
15
|
-
export { tsrSerializer } from '../serializer'
|
|
5
|
+
export * from './ssr-client'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createMemoryHistory } from '@tanstack/history'
|
|
2
2
|
import { mergeHeaders } from './headers'
|
|
3
|
-
import { attachRouterServerSsrUtils
|
|
3
|
+
import { attachRouterServerSsrUtils } from './ssr-server'
|
|
4
4
|
import type { HandlerCallback } from './handlerCallback'
|
|
5
5
|
import type { AnyRouter } from '../router'
|
|
6
6
|
import type { Manifest } from '../manifest'
|
|
@@ -39,7 +39,7 @@ export function createRequestHandler<TRouter extends AnyRouter>({
|
|
|
39
39
|
|
|
40
40
|
await router.load()
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
await router.serverSsr?.dehydrate()
|
|
43
43
|
|
|
44
44
|
const responseHeaders = getRequestHeaders({
|
|
45
45
|
router,
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { createPlugin } from 'seroval'
|
|
2
|
+
import type { SerovalNode } from 'seroval'
|
|
3
|
+
|
|
4
|
+
interface ErrorNode {
|
|
5
|
+
message: SerovalNode
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* this plugin serializes only the `message` part of an Error
|
|
10
|
+
* this helps with serializing e.g. a ZodError which has functions attached that cannot be serialized
|
|
11
|
+
*/
|
|
12
|
+
export const ShallowErrorPlugin = /* @__PURE__ */ createPlugin<
|
|
13
|
+
Error,
|
|
14
|
+
ErrorNode
|
|
15
|
+
>({
|
|
16
|
+
tag: 'tanstack-start:seroval-plugins/Error',
|
|
17
|
+
test(value) {
|
|
18
|
+
return value instanceof Error
|
|
19
|
+
},
|
|
20
|
+
parse: {
|
|
21
|
+
sync(value, ctx) {
|
|
22
|
+
return {
|
|
23
|
+
message: ctx.parse(value.message),
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
async async(value, ctx) {
|
|
27
|
+
return {
|
|
28
|
+
message: await ctx.parse(value.message),
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
stream(value, ctx) {
|
|
32
|
+
return {
|
|
33
|
+
message: ctx.parse(value.message),
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
serialize(node, ctx) {
|
|
38
|
+
return 'new Error(' + ctx.serialize(node.message) + ')'
|
|
39
|
+
},
|
|
40
|
+
deserialize(node, ctx) {
|
|
41
|
+
return new Error(ctx.deserialize(node.message) as string)
|
|
42
|
+
},
|
|
43
|
+
})
|
package/src/ssr/server.ts
CHANGED
|
@@ -7,17 +7,4 @@ export {
|
|
|
7
7
|
transformStreamWithRouter,
|
|
8
8
|
transformReadableStreamWithRouter,
|
|
9
9
|
} from './transformStreamWithRouter'
|
|
10
|
-
export {
|
|
11
|
-
attachRouterServerSsrUtils,
|
|
12
|
-
dehydrateRouter,
|
|
13
|
-
extractAsyncLoaderData,
|
|
14
|
-
onMatchSettled,
|
|
15
|
-
replaceBy,
|
|
16
|
-
} from './ssr-server'
|
|
17
|
-
export type {
|
|
18
|
-
ServerExtractedBaseEntry,
|
|
19
|
-
ServerExtractedEntry,
|
|
20
|
-
ServerExtractedPromise,
|
|
21
|
-
ServerExtractedStream,
|
|
22
|
-
} from './ssr-server'
|
|
23
|
-
export * from './tsrScript'
|
|
10
|
+
export { attachRouterServerSsrUtils } from './ssr-server'
|
package/src/ssr/ssr-client.ts
CHANGED
|
@@ -1,114 +1,62 @@
|
|
|
1
1
|
import invariant from 'tiny-invariant'
|
|
2
|
-
import { isPlainObject } from '../utils'
|
|
3
|
-
import { tsrSerializer } from '../serializer'
|
|
4
|
-
import type { DeferredPromiseState } from '../defer'
|
|
5
2
|
import type { MakeRouteMatch } from '../Matches'
|
|
6
|
-
import type { AnyRouter
|
|
3
|
+
import type { AnyRouter } from '../router'
|
|
7
4
|
import type { Manifest } from '../manifest'
|
|
8
5
|
import type { RouteContextOptions } from '../route'
|
|
6
|
+
import type { GLOBAL_TSR } from './ssr-server'
|
|
9
7
|
|
|
10
8
|
declare global {
|
|
11
9
|
interface Window {
|
|
12
|
-
|
|
10
|
+
[GLOBAL_TSR]?: TsrSsrGlobal
|
|
13
11
|
}
|
|
14
12
|
}
|
|
15
13
|
|
|
16
14
|
export interface TsrSsrGlobal {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
{
|
|
21
|
-
value: any
|
|
22
|
-
parsed: any
|
|
23
|
-
}
|
|
24
|
-
>
|
|
25
|
-
cleanScripts: () => void
|
|
26
|
-
dehydrated?: any
|
|
27
|
-
initMatch: (match: SsrMatch) => void
|
|
28
|
-
resolvePromise: (opts: {
|
|
29
|
-
matchId: string
|
|
30
|
-
id: number
|
|
31
|
-
promiseState: DeferredPromiseState<any>
|
|
32
|
-
}) => void
|
|
33
|
-
injectChunk: (opts: { matchId: string; id: number; chunk: string }) => void
|
|
34
|
-
closeStream: (opts: { matchId: string; id: number }) => void
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export interface SsrMatch {
|
|
38
|
-
id: string
|
|
39
|
-
__beforeLoadContext: string
|
|
40
|
-
loaderData?: string
|
|
41
|
-
error?: string
|
|
42
|
-
extracted?: Array<ClientExtractedEntry>
|
|
43
|
-
updatedAt: MakeRouteMatch['updatedAt']
|
|
44
|
-
status: MakeRouteMatch['status']
|
|
45
|
-
ssr?: boolean | 'data-only'
|
|
15
|
+
router?: DehydratedRouter
|
|
16
|
+
// clean scripts, shortened since this is sent for each streamed script
|
|
17
|
+
c: () => void
|
|
46
18
|
}
|
|
47
19
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export interface ClientExtractedBaseEntry {
|
|
63
|
-
type: string
|
|
64
|
-
path: Array<string>
|
|
20
|
+
function hydrateMatch(
|
|
21
|
+
deyhydratedMatch: DehydratedMatch,
|
|
22
|
+
): Partial<MakeRouteMatch> {
|
|
23
|
+
return {
|
|
24
|
+
id: deyhydratedMatch.i,
|
|
25
|
+
__beforeLoadContext: deyhydratedMatch.b,
|
|
26
|
+
loaderData: deyhydratedMatch.l,
|
|
27
|
+
status: deyhydratedMatch.s,
|
|
28
|
+
ssr: deyhydratedMatch.ssr,
|
|
29
|
+
updatedAt: deyhydratedMatch.u,
|
|
30
|
+
error: deyhydratedMatch.e,
|
|
31
|
+
}
|
|
65
32
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
33
|
+
export interface DehydratedMatch {
|
|
34
|
+
i: MakeRouteMatch['id']
|
|
35
|
+
b?: MakeRouteMatch['__beforeLoadContext']
|
|
36
|
+
l?: MakeRouteMatch['loaderData']
|
|
37
|
+
e?: MakeRouteMatch['error']
|
|
38
|
+
u: MakeRouteMatch['updatedAt']
|
|
39
|
+
s: MakeRouteMatch['status']
|
|
40
|
+
ssr?: MakeRouteMatch['ssr']
|
|
71
41
|
}
|
|
72
42
|
|
|
73
43
|
export interface DehydratedRouter {
|
|
74
44
|
manifest: Manifest | undefined
|
|
75
|
-
dehydratedData
|
|
76
|
-
lastMatchId
|
|
45
|
+
dehydratedData?: any
|
|
46
|
+
lastMatchId?: string
|
|
47
|
+
matches: Array<DehydratedMatch>
|
|
77
48
|
}
|
|
78
49
|
|
|
79
50
|
export async function hydrate(router: AnyRouter): Promise<any> {
|
|
80
51
|
invariant(
|
|
81
|
-
window
|
|
82
|
-
'Expected to find a dehydrated data on window.
|
|
52
|
+
window.$_TSR?.router,
|
|
53
|
+
'Expected to find a dehydrated data on window.$_TSR.router, but we did not. Please file an issue!',
|
|
83
54
|
)
|
|
84
55
|
|
|
85
|
-
const { manifest, dehydratedData, lastMatchId } =
|
|
86
|
-
window.__TSR_SSR__.dehydrated,
|
|
87
|
-
) as DehydratedRouter
|
|
56
|
+
const { manifest, dehydratedData, lastMatchId } = window.$_TSR.router
|
|
88
57
|
|
|
89
58
|
router.ssr = {
|
|
90
59
|
manifest,
|
|
91
|
-
serializer: tsrSerializer,
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
router.clientSsr = {
|
|
95
|
-
getStreamedValue: <T>(key: string): T | undefined => {
|
|
96
|
-
if (router.isServer) {
|
|
97
|
-
return undefined
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const streamedValue = window.__TSR_SSR__?.streamedValues[key]
|
|
101
|
-
|
|
102
|
-
if (!streamedValue) {
|
|
103
|
-
return
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
if (!streamedValue.parsed) {
|
|
107
|
-
streamedValue.parsed = router.ssr!.serializer.parse(streamedValue.value)
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return streamedValue.parsed
|
|
111
|
-
},
|
|
112
60
|
}
|
|
113
61
|
|
|
114
62
|
// Hydrate the router state
|
|
@@ -126,16 +74,15 @@ export async function hydrate(router: AnyRouter): Promise<any> {
|
|
|
126
74
|
// First step is to reyhdrate loaderData and __beforeLoadContext
|
|
127
75
|
let firstNonSsrMatchIndex: number | undefined = undefined
|
|
128
76
|
matches.forEach((match) => {
|
|
129
|
-
const dehydratedMatch = window
|
|
130
|
-
(d) => d.
|
|
77
|
+
const dehydratedMatch = window.$_TSR!.router!.matches.find(
|
|
78
|
+
(d) => d.i === match.id,
|
|
131
79
|
)
|
|
132
|
-
|
|
133
80
|
if (!dehydratedMatch) {
|
|
134
81
|
Object.assign(match, { dehydrated: false, ssr: false })
|
|
135
82
|
return
|
|
136
83
|
}
|
|
137
84
|
|
|
138
|
-
Object.assign(match, dehydratedMatch)
|
|
85
|
+
Object.assign(match, hydrateMatch(dehydratedMatch))
|
|
139
86
|
|
|
140
87
|
if (match.ssr === false) {
|
|
141
88
|
match._dehydrated = false
|
|
@@ -153,30 +100,6 @@ export async function hydrate(router: AnyRouter): Promise<any> {
|
|
|
153
100
|
if (match.ssr === false) {
|
|
154
101
|
return
|
|
155
102
|
}
|
|
156
|
-
|
|
157
|
-
// Handle beforeLoadContext
|
|
158
|
-
if (dehydratedMatch.__beforeLoadContext) {
|
|
159
|
-
match.__beforeLoadContext = router.ssr!.serializer.parse(
|
|
160
|
-
dehydratedMatch.__beforeLoadContext,
|
|
161
|
-
) as any
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// Handle loaderData
|
|
165
|
-
if (dehydratedMatch.loaderData) {
|
|
166
|
-
match.loaderData = router.ssr!.serializer.parse(
|
|
167
|
-
dehydratedMatch.loaderData,
|
|
168
|
-
)
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// Handle error
|
|
172
|
-
if (dehydratedMatch.error) {
|
|
173
|
-
match.error = router.ssr!.serializer.parse(dehydratedMatch.error)
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// Handle extracted
|
|
177
|
-
;(match as unknown as SsrMatch).extracted?.forEach((ex) => {
|
|
178
|
-
deepMutableSetByPath(match, ['loaderData', ...ex.path], ex.value)
|
|
179
|
-
})
|
|
180
103
|
})
|
|
181
104
|
|
|
182
105
|
router.__store.setState((s) => {
|
|
@@ -271,21 +194,5 @@ export async function hydrate(router: AnyRouter): Promise<any> {
|
|
|
271
194
|
})
|
|
272
195
|
})
|
|
273
196
|
}
|
|
274
|
-
|
|
275
197
|
return routeChunkPromise
|
|
276
198
|
}
|
|
277
|
-
|
|
278
|
-
function deepMutableSetByPath<T>(obj: T, path: Array<string>, value: any) {
|
|
279
|
-
// mutable set by path retaining array and object references
|
|
280
|
-
if (path.length === 1) {
|
|
281
|
-
;(obj as any)[path[0]!] = value
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
const [key, ...rest] = path
|
|
285
|
-
|
|
286
|
-
if (Array.isArray(obj)) {
|
|
287
|
-
deepMutableSetByPath(obj[Number(key)], rest, value)
|
|
288
|
-
} else if (isPlainObject(obj)) {
|
|
289
|
-
deepMutableSetByPath((obj as any)[key!], rest, value)
|
|
290
|
-
}
|
|
291
|
-
}
|