@trpc/next 11.0.0-alpha-tmp-nosideeffects.257 → 11.0.0-alpha-tmp-02-08-tmp.274
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/README.md +1 -1
- package/dist/app-dir/create-action-hook.d.ts +2 -2
- package/dist/app-dir/create-action-hook.d.ts.map +1 -1
- package/dist/app-dir/links/nextCache.d.ts +2 -2
- package/dist/app-dir/links/nextCache.d.ts.map +1 -1
- package/dist/app-dir/server.d.ts +2 -2
- package/dist/app-dir/server.d.ts.map +1 -1
- package/dist/app-dir/shared.d.ts +8 -3
- package/dist/app-dir/shared.d.ts.map +1 -1
- package/dist/app-dir/types.d.ts +21 -9
- package/dist/app-dir/types.d.ts.map +1 -1
- package/dist/bundle-analysis.json +158 -0
- package/dist/createTRPCNext.d.ts +2 -2
- package/dist/createTRPCNext.d.ts.map +1 -1
- package/dist/ssrPrepass.d.ts +3 -0
- package/dist/ssrPrepass.d.ts.map +1 -0
- package/dist/ssrPrepass.js +139 -0
- package/dist/ssrPrepass.mjs +137 -0
- package/dist/withTRPC.d.ts +29 -3
- package/dist/withTRPC.d.ts.map +1 -1
- package/dist/withTRPC.js +7 -130
- package/dist/withTRPC.mjs +9 -132
- package/package.json +14 -8
- package/src/app-dir/create-action-hook.tsx +2 -2
- package/src/app-dir/links/nextCache.ts +2 -2
- package/src/app-dir/server.ts +2 -2
- package/src/app-dir/shared.ts +9 -3
- package/src/app-dir/types.ts +27 -13
- package/src/createTRPCNext.tsx +2 -5
- package/src/ssrPrepass.ts +185 -0
- package/src/withTRPC.tsx +39 -185
- package/ssrPrepass/index.d.ts +1 -0
- package/ssrPrepass/index.js +1 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Heavily based on urql's ssr
|
|
3
|
+
* https://github.com/FormidableLabs/urql/blob/main/packages/next-urql/src/with-urql-client.ts
|
|
4
|
+
*/
|
|
5
|
+
import type { DehydratedState } from '@tanstack/react-query';
|
|
6
|
+
import { dehydrate } from '@tanstack/react-query';
|
|
7
|
+
import { createTRPCUntypedClient } from '@trpc/client';
|
|
8
|
+
import type { CoercedTransformerParameters } from '@trpc/client/unstable-internals';
|
|
9
|
+
import { getTransformer } from '@trpc/client/unstable-internals';
|
|
10
|
+
import type { TRPCClientError, TRPCClientErrorLike } from '@trpc/react-query';
|
|
11
|
+
import { getQueryClient } from '@trpc/react-query/shared';
|
|
12
|
+
import type {
|
|
13
|
+
AnyRouter,
|
|
14
|
+
Dict,
|
|
15
|
+
Maybe,
|
|
16
|
+
} from '@trpc/server/unstable-core-do-not-import';
|
|
17
|
+
import type {
|
|
18
|
+
AppContextType,
|
|
19
|
+
NextPageContext,
|
|
20
|
+
} from 'next/dist/shared/lib/utils';
|
|
21
|
+
import { createElement } from 'react';
|
|
22
|
+
import type { TRPCPrepassHelper, TRPCPrepassProps } from './withTRPC';
|
|
23
|
+
|
|
24
|
+
function transformQueryOrMutationCacheErrors<
|
|
25
|
+
TState extends
|
|
26
|
+
| DehydratedState['mutations'][0]
|
|
27
|
+
| DehydratedState['queries'][0],
|
|
28
|
+
>(result: TState): TState {
|
|
29
|
+
const error = result.state.error as Maybe<TRPCClientError<any>>;
|
|
30
|
+
if (error instanceof Error && error.name === 'TRPCClientError') {
|
|
31
|
+
const newError: TRPCClientErrorLike<any> = {
|
|
32
|
+
message: error.message,
|
|
33
|
+
data: error.data,
|
|
34
|
+
shape: error.shape,
|
|
35
|
+
};
|
|
36
|
+
return {
|
|
37
|
+
...result,
|
|
38
|
+
state: {
|
|
39
|
+
...result.state,
|
|
40
|
+
error: newError,
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export const ssrPrepass: TRPCPrepassHelper = (opts) => {
|
|
48
|
+
const { parent, WithTRPC, AppOrPage } = opts;
|
|
49
|
+
type $PrepassProps = TRPCPrepassProps<AnyRouter, any>;
|
|
50
|
+
|
|
51
|
+
const transformer = getTransformer(
|
|
52
|
+
(parent as CoercedTransformerParameters).transformer,
|
|
53
|
+
);
|
|
54
|
+
WithTRPC.getInitialProps = async (appOrPageCtx: AppContextType) => {
|
|
55
|
+
const shouldSsr = async () => {
|
|
56
|
+
if (typeof window !== 'undefined') {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
if (typeof parent.ssr === 'function') {
|
|
60
|
+
try {
|
|
61
|
+
return await parent.ssr({ ctx: appOrPageCtx.ctx });
|
|
62
|
+
} catch (e) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return parent.ssr;
|
|
67
|
+
};
|
|
68
|
+
const ssrEnabled = await shouldSsr();
|
|
69
|
+
const AppTree = appOrPageCtx.AppTree;
|
|
70
|
+
|
|
71
|
+
// Determine if we are wrapping an App component or a Page component.
|
|
72
|
+
const isApp = !!appOrPageCtx.Component;
|
|
73
|
+
const ctx: NextPageContext = isApp
|
|
74
|
+
? appOrPageCtx.ctx
|
|
75
|
+
: (appOrPageCtx as any as NextPageContext);
|
|
76
|
+
|
|
77
|
+
// Run the wrapped component's getInitialProps function.
|
|
78
|
+
let pageProps: Dict<unknown> = {};
|
|
79
|
+
if (AppOrPage.getInitialProps) {
|
|
80
|
+
const originalProps = await AppOrPage.getInitialProps(
|
|
81
|
+
appOrPageCtx as any,
|
|
82
|
+
);
|
|
83
|
+
const originalPageProps = isApp
|
|
84
|
+
? originalProps.pageProps ?? {}
|
|
85
|
+
: originalProps;
|
|
86
|
+
|
|
87
|
+
pageProps = {
|
|
88
|
+
...originalPageProps,
|
|
89
|
+
...pageProps,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
const getAppTreeProps = (props: Record<string, unknown>) =>
|
|
93
|
+
isApp ? { pageProps: props } : props;
|
|
94
|
+
|
|
95
|
+
if (typeof window !== 'undefined' || !ssrEnabled) {
|
|
96
|
+
return getAppTreeProps(pageProps);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const config = parent.config({ ctx });
|
|
100
|
+
const trpcClient = createTRPCUntypedClient(config);
|
|
101
|
+
const queryClient = getQueryClient(config);
|
|
102
|
+
|
|
103
|
+
const trpcProp: $PrepassProps = {
|
|
104
|
+
config,
|
|
105
|
+
trpcClient,
|
|
106
|
+
queryClient,
|
|
107
|
+
ssrState: 'prepass',
|
|
108
|
+
ssrContext: ctx,
|
|
109
|
+
};
|
|
110
|
+
const prepassProps = {
|
|
111
|
+
pageProps,
|
|
112
|
+
trpc: trpcProp,
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const reactDomServer = await import('react-dom/server');
|
|
116
|
+
|
|
117
|
+
// Run the prepass step on AppTree. This will run all trpc queries on the server.
|
|
118
|
+
// multiple prepass ensures that we can do batching on the server
|
|
119
|
+
while (true) {
|
|
120
|
+
// render full tree
|
|
121
|
+
reactDomServer.renderToString(createElement(AppTree, prepassProps));
|
|
122
|
+
if (!queryClient.isFetching()) {
|
|
123
|
+
// the render didn't cause the queryClient to fetch anything
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// wait until the query cache has settled it's promises
|
|
128
|
+
await new Promise<void>((resolve) => {
|
|
129
|
+
const unsub = queryClient.getQueryCache().subscribe((event) => {
|
|
130
|
+
if (event?.query.getObserversCount() === 0) {
|
|
131
|
+
resolve();
|
|
132
|
+
unsub();
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
const dehydratedCache = dehydrate(queryClient, {
|
|
138
|
+
shouldDehydrateQuery(query) {
|
|
139
|
+
// filter out queries that are marked as trpc: { ssr: false } or are not enabled, but make sure errors are dehydrated
|
|
140
|
+
const isExcludedFromSSr =
|
|
141
|
+
query.state.fetchStatus === 'idle' &&
|
|
142
|
+
query.state.status === 'pending';
|
|
143
|
+
return !isExcludedFromSSr;
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
// since error instances can't be serialized, let's make them into `TRPCClientErrorLike`-objects
|
|
147
|
+
const dehydratedCacheWithErrors = {
|
|
148
|
+
...dehydratedCache,
|
|
149
|
+
queries: dehydratedCache.queries.map(transformQueryOrMutationCacheErrors),
|
|
150
|
+
mutations: dehydratedCache.mutations.map(
|
|
151
|
+
transformQueryOrMutationCacheErrors,
|
|
152
|
+
),
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
// dehydrate query client's state and add it to the props
|
|
156
|
+
pageProps['trpcState'] = transformer.input.serialize(
|
|
157
|
+
dehydratedCacheWithErrors,
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
const appTreeProps = getAppTreeProps(pageProps);
|
|
161
|
+
|
|
162
|
+
const meta =
|
|
163
|
+
parent.responseMeta?.({
|
|
164
|
+
ctx,
|
|
165
|
+
clientErrors: [...dehydratedCache.queries, ...dehydratedCache.mutations]
|
|
166
|
+
.map((v) => v.state.error)
|
|
167
|
+
.flatMap((err) =>
|
|
168
|
+
err instanceof Error && err.name === 'TRPCClientError'
|
|
169
|
+
? [err as TRPCClientError<AnyRouter>]
|
|
170
|
+
: [],
|
|
171
|
+
),
|
|
172
|
+
}) ?? {};
|
|
173
|
+
|
|
174
|
+
for (const [key, value] of Object.entries(meta.headers ?? {})) {
|
|
175
|
+
if (typeof value === 'string') {
|
|
176
|
+
ctx.res?.setHeader(key, value);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (meta.status && ctx.res) {
|
|
180
|
+
ctx.res.statusCode = meta.status;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return appTreeProps;
|
|
184
|
+
};
|
|
185
|
+
};
|
package/src/withTRPC.tsx
CHANGED
|
@@ -3,19 +3,14 @@
|
|
|
3
3
|
* https://github.com/FormidableLabs/urql/blob/main/packages/next-urql/src/with-urql-client.ts
|
|
4
4
|
*/
|
|
5
5
|
import type { DehydratedState, QueryClient } from '@tanstack/react-query';
|
|
6
|
-
import {
|
|
7
|
-
dehydrate,
|
|
8
|
-
HydrationBoundary,
|
|
9
|
-
QueryClientProvider,
|
|
10
|
-
} from '@tanstack/react-query';
|
|
6
|
+
import { HydrationBoundary, QueryClientProvider } from '@tanstack/react-query';
|
|
11
7
|
import type { CreateTRPCClientOptions, TRPCUntypedClient } from '@trpc/client';
|
|
12
|
-
import { createTRPCUntypedClient } from '@trpc/client';
|
|
13
8
|
import type { CoercedTransformerParameters } from '@trpc/client/unstable-internals';
|
|
14
9
|
import {
|
|
15
10
|
getTransformer,
|
|
16
11
|
type TransformerOptions,
|
|
17
12
|
} from '@trpc/client/unstable-internals';
|
|
18
|
-
import type { TRPCClientError
|
|
13
|
+
import type { TRPCClientError } from '@trpc/react-query';
|
|
19
14
|
import type {
|
|
20
15
|
CreateTRPCReactOptions,
|
|
21
16
|
CreateTRPCReactQueryClientConfig,
|
|
@@ -23,42 +18,17 @@ import type {
|
|
|
23
18
|
import { createRootHooks, getQueryClient } from '@trpc/react-query/shared';
|
|
24
19
|
import type {
|
|
25
20
|
AnyRouter,
|
|
26
|
-
|
|
27
|
-
inferRootTypes,
|
|
28
|
-
Maybe,
|
|
21
|
+
inferClientTypes,
|
|
29
22
|
ResponseMeta,
|
|
30
23
|
} from '@trpc/server/unstable-core-do-not-import';
|
|
31
24
|
import type {
|
|
32
|
-
AppContextType,
|
|
33
25
|
AppPropsType,
|
|
34
26
|
NextComponentType,
|
|
35
27
|
NextPageContext,
|
|
36
28
|
} from 'next/dist/shared/lib/utils';
|
|
37
29
|
import type { NextRouter } from 'next/router';
|
|
38
|
-
import React, {
|
|
30
|
+
import React, { useState } from 'react';
|
|
39
31
|
|
|
40
|
-
function transformQueryOrMutationCacheErrors<
|
|
41
|
-
TState extends
|
|
42
|
-
| DehydratedState['mutations'][0]
|
|
43
|
-
| DehydratedState['queries'][0],
|
|
44
|
-
>(result: TState): TState {
|
|
45
|
-
const error = result.state.error as Maybe<TRPCClientError<any>>;
|
|
46
|
-
if (error instanceof Error && error.name === 'TRPCClientError') {
|
|
47
|
-
const newError: TRPCClientErrorLike<any> = {
|
|
48
|
-
message: error.message,
|
|
49
|
-
data: error.data,
|
|
50
|
-
shape: error.shape,
|
|
51
|
-
};
|
|
52
|
-
return {
|
|
53
|
-
...result,
|
|
54
|
-
state: {
|
|
55
|
-
...result.state,
|
|
56
|
-
error: newError,
|
|
57
|
-
},
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
return result;
|
|
61
|
-
}
|
|
62
32
|
export type WithTRPCConfig<TRouter extends AnyRouter> =
|
|
63
33
|
CreateTRPCClientOptions<TRouter> &
|
|
64
34
|
CreateTRPCReactQueryClientConfig & {
|
|
@@ -68,10 +38,19 @@ export type WithTRPCConfig<TRouter extends AnyRouter> =
|
|
|
68
38
|
type WithTRPCOptions<TRouter extends AnyRouter> =
|
|
69
39
|
CreateTRPCReactOptions<TRouter> & {
|
|
70
40
|
config: (info: { ctx?: NextPageContext }) => WithTRPCConfig<TRouter>;
|
|
71
|
-
} & TransformerOptions<
|
|
41
|
+
} & TransformerOptions<inferClientTypes<TRouter>>;
|
|
72
42
|
|
|
43
|
+
export type TRPCPrepassHelper = (opts: {
|
|
44
|
+
parent: WithTRPCSSROptions<AnyRouter>;
|
|
45
|
+
WithTRPC: NextComponentType<any, any, any>;
|
|
46
|
+
AppOrPage: NextComponentType<any, any, any>;
|
|
47
|
+
}) => void;
|
|
73
48
|
export type WithTRPCSSROptions<TRouter extends AnyRouter> =
|
|
74
49
|
WithTRPCOptions<TRouter> & {
|
|
50
|
+
/**
|
|
51
|
+
* If you enable this, you also need to add a `ssrPrepass`-prop
|
|
52
|
+
* @link https://trpc.io/docs/client/nextjs/ssr
|
|
53
|
+
*/
|
|
75
54
|
ssr:
|
|
76
55
|
| true
|
|
77
56
|
| ((opts: { ctx: NextPageContext }) => boolean | Promise<boolean>);
|
|
@@ -79,6 +58,11 @@ export type WithTRPCSSROptions<TRouter extends AnyRouter> =
|
|
|
79
58
|
ctx: NextPageContext;
|
|
80
59
|
clientErrors: TRPCClientError<TRouter>[];
|
|
81
60
|
}) => ResponseMeta;
|
|
61
|
+
/**
|
|
62
|
+
* use `import { ssrPrepass } from '@trpc/next/ssrPrepass'`
|
|
63
|
+
* @link https://trpc.io/docs/client/nextjs/ssr
|
|
64
|
+
*/
|
|
65
|
+
ssrPrepass: TRPCPrepassHelper;
|
|
82
66
|
};
|
|
83
67
|
|
|
84
68
|
export type WithTRPCNoSSROptions<TRouter extends AnyRouter> =
|
|
@@ -86,6 +70,17 @@ export type WithTRPCNoSSROptions<TRouter extends AnyRouter> =
|
|
|
86
70
|
ssr?: false;
|
|
87
71
|
};
|
|
88
72
|
|
|
73
|
+
export type TRPCPrepassProps<
|
|
74
|
+
TRouter extends AnyRouter,
|
|
75
|
+
TSSRContext extends NextPageContext = NextPageContext,
|
|
76
|
+
> = {
|
|
77
|
+
config: WithTRPCConfig<TRouter>;
|
|
78
|
+
queryClient: QueryClient;
|
|
79
|
+
trpcClient: TRPCUntypedClient<TRouter>;
|
|
80
|
+
ssrState: 'prepass';
|
|
81
|
+
ssrContext: TSSRContext;
|
|
82
|
+
};
|
|
83
|
+
|
|
89
84
|
export function withTRPC<
|
|
90
85
|
TRouter extends AnyRouter,
|
|
91
86
|
TSSRContext extends NextPageContext = NextPageContext,
|
|
@@ -95,19 +90,13 @@ export function withTRPC<
|
|
|
95
90
|
(opts as CoercedTransformerParameters).transformer,
|
|
96
91
|
);
|
|
97
92
|
|
|
98
|
-
type
|
|
99
|
-
config: WithTRPCConfig<TRouter>;
|
|
100
|
-
queryClient: QueryClient;
|
|
101
|
-
trpcClient: TRPCUntypedClient<TRouter>;
|
|
102
|
-
ssrState: 'prepass';
|
|
103
|
-
ssrContext: TSSRContext;
|
|
104
|
-
};
|
|
93
|
+
type $PrepassProps = TRPCPrepassProps<TRouter, TSSRContext>;
|
|
105
94
|
return (AppOrPage: NextComponentType<any, any, any>): NextComponentType => {
|
|
106
95
|
const trpc = createRootHooks<TRouter, TSSRContext>(opts);
|
|
107
96
|
|
|
108
|
-
const WithTRPC =
|
|
97
|
+
const WithTRPC = (
|
|
109
98
|
props: AppPropsType<NextRouter, any> & {
|
|
110
|
-
trpc?:
|
|
99
|
+
trpc?: $PrepassProps;
|
|
111
100
|
},
|
|
112
101
|
) => {
|
|
113
102
|
const [prepassProps] = useState(() => {
|
|
@@ -159,147 +148,12 @@ export function withTRPC<
|
|
|
159
148
|
);
|
|
160
149
|
};
|
|
161
150
|
|
|
162
|
-
if (
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}
|
|
169
|
-
try {
|
|
170
|
-
return await opts.ssr({ ctx: appOrPageCtx.ctx });
|
|
171
|
-
} catch (e) {
|
|
172
|
-
return false;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
return opts.ssr;
|
|
176
|
-
};
|
|
177
|
-
const ssr = await shouldSsr();
|
|
178
|
-
const AppTree = appOrPageCtx.AppTree;
|
|
179
|
-
|
|
180
|
-
// Determine if we are wrapping an App component or a Page component.
|
|
181
|
-
const isApp = !!appOrPageCtx.Component;
|
|
182
|
-
const ctx: NextPageContext = isApp
|
|
183
|
-
? appOrPageCtx.ctx
|
|
184
|
-
: (appOrPageCtx as any as NextPageContext);
|
|
185
|
-
|
|
186
|
-
// Run the wrapped component's getInitialProps function.
|
|
187
|
-
let pageProps: Dict<unknown> = {};
|
|
188
|
-
if (AppOrPage.getInitialProps) {
|
|
189
|
-
const originalProps = await AppOrPage.getInitialProps(
|
|
190
|
-
appOrPageCtx as any,
|
|
191
|
-
);
|
|
192
|
-
const originalPageProps = isApp
|
|
193
|
-
? originalProps.pageProps ?? {}
|
|
194
|
-
: originalProps;
|
|
195
|
-
|
|
196
|
-
pageProps = {
|
|
197
|
-
...originalPageProps,
|
|
198
|
-
...pageProps,
|
|
199
|
-
};
|
|
200
|
-
}
|
|
201
|
-
const getAppTreeProps = (props: Record<string, unknown>) =>
|
|
202
|
-
isApp ? { pageProps: props } : props;
|
|
203
|
-
|
|
204
|
-
if (typeof window !== 'undefined' || !ssr) {
|
|
205
|
-
return getAppTreeProps(pageProps);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
const config = getClientConfig({ ctx });
|
|
209
|
-
const trpcClient = createTRPCUntypedClient(config);
|
|
210
|
-
const queryClient = getQueryClient(config);
|
|
211
|
-
|
|
212
|
-
const trpcProp: TRPCPrepassProps = {
|
|
213
|
-
config,
|
|
214
|
-
trpcClient,
|
|
215
|
-
queryClient,
|
|
216
|
-
ssrState: 'prepass',
|
|
217
|
-
ssrContext: ctx as TSSRContext,
|
|
218
|
-
};
|
|
219
|
-
const prepassProps = {
|
|
220
|
-
pageProps,
|
|
221
|
-
trpc: trpcProp,
|
|
222
|
-
};
|
|
223
|
-
|
|
224
|
-
const reactDomServer = /** __@PURE__ */ await import(
|
|
225
|
-
'react-dom/server'
|
|
226
|
-
);
|
|
227
|
-
|
|
228
|
-
// Run the prepass step on AppTree. This will run all trpc queries on the server.
|
|
229
|
-
// multiple prepass ensures that we can do batching on the server
|
|
230
|
-
while (true) {
|
|
231
|
-
// render full tree
|
|
232
|
-
reactDomServer.renderToString(createElement(AppTree, prepassProps));
|
|
233
|
-
if (!queryClient.isFetching()) {
|
|
234
|
-
// the render didn't cause the queryClient to fetch anything
|
|
235
|
-
break;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// wait until the query cache has settled it's promises
|
|
239
|
-
await new Promise<void>((resolve) => {
|
|
240
|
-
const unsub = queryClient.getQueryCache().subscribe((event) => {
|
|
241
|
-
if (event?.query.getObserversCount() === 0) {
|
|
242
|
-
resolve();
|
|
243
|
-
unsub();
|
|
244
|
-
}
|
|
245
|
-
});
|
|
246
|
-
});
|
|
247
|
-
}
|
|
248
|
-
const dehydratedCache = dehydrate(queryClient, {
|
|
249
|
-
shouldDehydrateQuery(query) {
|
|
250
|
-
// filter out queries that are marked as trpc: { ssr: false } or are not enabled, but make sure errors are dehydrated
|
|
251
|
-
const isExcludedFromSSr =
|
|
252
|
-
query.state.fetchStatus === 'idle' &&
|
|
253
|
-
query.state.status === 'pending';
|
|
254
|
-
return !isExcludedFromSSr;
|
|
255
|
-
},
|
|
256
|
-
});
|
|
257
|
-
// since error instances can't be serialized, let's make them into `TRPCClientErrorLike`-objects
|
|
258
|
-
const dehydratedCacheWithErrors = {
|
|
259
|
-
...dehydratedCache,
|
|
260
|
-
queries: dehydratedCache.queries.map(
|
|
261
|
-
transformQueryOrMutationCacheErrors,
|
|
262
|
-
),
|
|
263
|
-
mutations: dehydratedCache.mutations.map(
|
|
264
|
-
transformQueryOrMutationCacheErrors,
|
|
265
|
-
),
|
|
266
|
-
};
|
|
267
|
-
|
|
268
|
-
// dehydrate query client's state and add it to the props
|
|
269
|
-
pageProps['trpcState'] = transformer.input.serialize(
|
|
270
|
-
dehydratedCacheWithErrors,
|
|
271
|
-
);
|
|
272
|
-
|
|
273
|
-
const appTreeProps = getAppTreeProps(pageProps);
|
|
274
|
-
|
|
275
|
-
if ('responseMeta' in opts) {
|
|
276
|
-
const meta =
|
|
277
|
-
opts.responseMeta?.({
|
|
278
|
-
ctx,
|
|
279
|
-
clientErrors: [
|
|
280
|
-
...dehydratedCache.queries,
|
|
281
|
-
...dehydratedCache.mutations,
|
|
282
|
-
]
|
|
283
|
-
.map((v) => v.state.error)
|
|
284
|
-
.flatMap((err) =>
|
|
285
|
-
err instanceof Error && err.name === 'TRPCClientError'
|
|
286
|
-
? [err as TRPCClientError<TRouter>]
|
|
287
|
-
: [],
|
|
288
|
-
),
|
|
289
|
-
}) ?? {};
|
|
290
|
-
|
|
291
|
-
for (const [key, value] of Object.entries(meta.headers ?? {})) {
|
|
292
|
-
if (typeof value === 'string') {
|
|
293
|
-
ctx.res?.setHeader(key, value);
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
if (meta.status && ctx.res) {
|
|
297
|
-
ctx.res.statusCode = meta.status;
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
return appTreeProps;
|
|
302
|
-
};
|
|
151
|
+
if (opts.ssr) {
|
|
152
|
+
opts.ssrPrepass({
|
|
153
|
+
parent: opts,
|
|
154
|
+
AppOrPage,
|
|
155
|
+
WithTRPC,
|
|
156
|
+
});
|
|
303
157
|
}
|
|
304
158
|
|
|
305
159
|
const displayName = AppOrPage.displayName ?? AppOrPage.name ?? 'Component';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '../dist/ssrPrepass';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('../dist/ssrPrepass');
|