@@ -39,100 +39,93 @@ export function routerWithQueryClient<TRouter extends AnyRouter>(
39
39
queryClient : QueryClient ,
40
40
additionalOpts ?: AdditionalOptions ,
41
41
) : TRouter {
42
+ const ogOptions = router . options
43
+
44
+ router . options = {
45
+ ...router . options ,
46
+ context : {
47
+ ...ogOptions . context ,
48
+ // Pass the query client to the context, so we can access it in loaders
49
+ queryClient,
50
+ } ,
51
+ // Wrap the app in a QueryClientProvider
52
+ Wrap : ( { children } ) => {
53
+ const OuterWrapper = additionalOpts ?. WrapProvider || Fragment
54
+ const OGWrap = ogOptions . Wrap || Fragment
55
+ return (
56
+ < OuterWrapper >
57
+ < QueryClientProvider client = { queryClient } >
58
+ < OGWrap > { children } </ OGWrap >
59
+ </ QueryClientProvider >
60
+ </ OuterWrapper >
61
+ )
62
+ } ,
63
+ }
64
+
42
65
let queryStream : PushableStream
43
66
44
67
if ( router . isServer ) {
45
- queryStream = createPushableStream ( )
46
- }
68
+ router . options . dehydrate =
69
+ async ( ) : Promise < DehydratedRouterQueryState > => {
70
+ const ogDehydrated = await ogOptions . dehydrate ?.( )
71
+ const dehydratedQueryClient = queryDehydrate ( queryClient )
47
72
48
- const ogClientOptions = queryClient . getDefaultOptions ( )
49
- queryClient . setDefaultOptions ( {
50
- ...ogClientOptions ,
51
- dehydrate : {
52
- shouldDehydrateQuery : ( ) => true ,
53
- ...ogClientOptions . dehydrate ,
54
- } ,
55
- } )
73
+ router . serverSsr ! . onRenderFinished ( ( ) => queryStream . close ( ) )
56
74
57
- if ( additionalOpts ?. handleRedirects ?? true ) {
58
- const ogMutationCacheConfig = queryClient . getMutationCache ( ) . config
59
- queryClient . getMutationCache ( ) . config = {
60
- ...ogMutationCacheConfig ,
61
- onError : ( error , _variables , _context , _mutation ) => {
62
- if ( isRedirect ( error ) ) {
63
- error . options . _fromLocation = router . state . location
64
- return router . navigate ( router . resolveRedirect ( error ) . options )
75
+ const dehydratedRouter = {
76
+ ...ogDehydrated ,
77
+ // When critical data is dehydrated, we also dehydrate the query client
78
+ dehydratedQueryClient,
79
+ // prepare the stream for queries coming up during rendering
80
+ queryStream : queryStream . stream ,
65
81
}
66
82
67
- return ogMutationCacheConfig . onError ?.(
68
- error ,
69
- _variables ,
70
- _context ,
71
- _mutation ,
72
- )
73
- } ,
74
- }
83
+ return dehydratedRouter
84
+ }
75
85
76
- const ogQueryCacheConfig = queryClient . getQueryCache ( ) . config
77
- queryClient . getQueryCache ( ) . config = {
78
- ...ogQueryCacheConfig ,
79
- onError : ( error , _query ) => {
80
- if ( isRedirect ( error ) ) {
81
- error . options . _fromLocation = router . state . location
82
- return router . navigate ( router . resolveRedirect ( error ) . options )
83
- }
86
+ queryStream = createPushableStream ( )
84
87
85
- return ogQueryCacheConfig . onError ?.( error , _query )
88
+ const ogClientOptions = queryClient . getDefaultOptions ( )
89
+ queryClient . setDefaultOptions ( {
90
+ ...ogClientOptions ,
91
+ dehydrate : {
92
+ shouldDehydrateQuery : ( ) => true ,
93
+ ...ogClientOptions . dehydrate ,
86
94
} ,
87
- }
88
- if ( router . isServer ) {
89
- queryClient . getQueryCache ( ) . subscribe ( ( event ) => {
90
- if ( event . type === 'added' ) {
91
- if ( ! router . serverSsr ! . isDehydrated ( ) ) {
92
- return
93
- }
94
- if ( queryStream ! . isClosed ) {
95
- console . warn (
96
- `tried to stream query ${ event . query . queryHash } after stream was already closed` ,
97
- )
98
- }
99
- queryStream ! . enqueue (
100
- queryDehydrate ( queryClient , {
101
- shouldDehydrateQuery : ( query ) => {
102
- if ( query . queryHash === event . query . queryHash ) {
103
- return (
104
- ogClientOptions . dehydrate ?. shouldDehydrateQuery ?.( query ) ??
105
- true
106
- )
107
- }
108
- return false
109
- } ,
110
- } ) ,
95
+ } )
96
+
97
+ queryClient . getQueryCache ( ) . subscribe ( ( event ) => {
98
+ if ( event . type === 'added' ) {
99
+ if ( ! router . serverSsr ! . isDehydrated ( ) ) {
100
+ return
101
+ }
102
+ if ( queryStream ! . isClosed ) {
103
+ console . warn (
104
+ `tried to stream query ${ event . query . queryHash } after stream was already closed` ,
111
105
)
112
106
}
113
- } )
114
- }
115
- }
116
-
117
- const ogOptions = router . options
118
- router . options = {
119
- ...router . options ,
120
- dehydrate : async ( ) : Promise < DehydratedRouterQueryState > => {
121
- router . serverSsr ! . onRenderFinished ( ( ) => queryStream . close ( ) )
122
- const ogDehydrated = await ogOptions . dehydrate ?.( )
123
- return {
124
- ...ogDehydrated ,
125
- // When critical data is dehydrated, we also dehydrate the query client
126
- dehydratedQueryClient : queryDehydrate ( queryClient ) ,
127
- // prepare the stream for queries coming up during rendering
128
- queryStream : queryStream . stream ,
107
+ queryStream ! . enqueue (
108
+ queryDehydrate ( queryClient , {
109
+ shouldDehydrateQuery : ( query ) => {
110
+ if ( query . queryHash === event . query . queryHash ) {
111
+ return (
112
+ ogClientOptions . dehydrate ?. shouldDehydrateQuery ?.( query ) ??
113
+ true
114
+ )
115
+ }
116
+ return false
117
+ } ,
118
+ } ) ,
119
+ )
129
120
}
130
- } ,
131
- hydrate : async ( dehydrated : DehydratedRouterQueryState ) => {
132
- console . log ( 'dehydrated' , dehydrated )
121
+ } )
122
+ // on the client
123
+ } else {
124
+ router . options . hydrate = async ( dehydrated : DehydratedRouterQueryState ) => {
133
125
await ogOptions . hydrate ?.( dehydrated )
134
126
// On the client, hydrate the query client with the dehydrated data
135
127
queryHydrate ( queryClient , dehydrated . dehydratedQueryClient )
128
+
136
129
const reader = dehydrated . queryStream . getReader ( )
137
130
reader . read ( ) . then ( function handle ( { done, value } ) : Promise < void > {
138
131
queryHydrate ( queryClient , value )
@@ -141,24 +134,39 @@ export function routerWithQueryClient<TRouter extends AnyRouter>(
141
134
}
142
135
return reader . read ( ) . then ( handle )
143
136
} )
144
- } ,
145
- context : {
146
- ...ogOptions . context ,
147
- // Pass the query client to the context, so we can access it in loaders
148
- queryClient,
149
- } ,
150
- // Wrap the app in a QueryClientProvider
151
- Wrap : ( { children } ) => {
152
- const OuterWrapper = additionalOpts ?. WrapProvider || Fragment
153
- const OGWrap = ogOptions . Wrap || Fragment
154
- return (
155
- < OuterWrapper >
156
- < QueryClientProvider client = { queryClient } >
157
- < OGWrap > { children } </ OGWrap >
158
- </ QueryClientProvider >
159
- </ OuterWrapper >
160
- )
161
- } ,
137
+ }
138
+ if ( additionalOpts ?. handleRedirects ?? true ) {
139
+ const ogMutationCacheConfig = queryClient . getMutationCache ( ) . config
140
+ queryClient . getMutationCache ( ) . config = {
141
+ ...ogMutationCacheConfig ,
142
+ onError : ( error , _variables , _context , _mutation ) => {
143
+ if ( isRedirect ( error ) ) {
144
+ error . options . _fromLocation = router . state . location
145
+ return router . navigate ( router . resolveRedirect ( error ) . options )
146
+ }
147
+
148
+ return ogMutationCacheConfig . onError ?.(
149
+ error ,
150
+ _variables ,
151
+ _context ,
152
+ _mutation ,
153
+ )
154
+ } ,
155
+ }
156
+
157
+ const ogQueryCacheConfig = queryClient . getQueryCache ( ) . config
158
+ queryClient . getQueryCache ( ) . config = {
159
+ ...ogQueryCacheConfig ,
160
+ onError : ( error , _query ) => {
161
+ if ( isRedirect ( error ) ) {
162
+ error . options . _fromLocation = router . state . location
163
+ return router . navigate ( router . resolveRedirect ( error ) . options )
164
+ }
165
+
166
+ return ogQueryCacheConfig . onError ?.( error , _query )
167
+ } ,
168
+ }
169
+ }
162
170
}
163
171
164
172
return router
@@ -171,6 +179,7 @@ type PushableStream = {
171
179
isClosed : boolean
172
180
error : ( err : unknown ) => void
173
181
}
182
+
174
183
function createPushableStream ( ) : PushableStream {
175
184
let controllerRef : ReadableStreamDefaultController | undefined
176
185
const stream = new ReadableStream ( {
0 commit comments