メインコンテンツにスキップ
バージョン: 11.x

サーバーサイドレンダリング

SSR を有効にするには、createTRPCNext 設定コールバックで ssr: true を設定するだけです。

{/* SVGアイコンは翻訳不要 */}情報

SSR を有効にすると、tRPC は getInitialProps を使用してサーバー上のすべてのクエリをプリフェッチします。これは、getServerSideProps を使用するとこのような問題が発生し、解決は我々の手には負えません。

 
代わりに、SSR を無効のままにして (デフォルト)、サーバーサイドヘルパーを使用して、getStaticProps または getServerSideProps でクエリをプリフェッチすることもできます。

サーバーサイドレンダリングステップ中にクエリを適切に実行するには、config 内に特別なロジックを追加する必要があります

さらに、レスポンスキャッシングも検討してください。

utils/trpc.ts
tsx
import { httpBatchLink } from '@trpc/client';
import { createTRPCNext } from '@trpc/next';
import { ssrPrepass } from '@trpc/next/ssrPrepass';
import superjson from 'superjson';
import type { AppRouter } from './api/trpc/[trpc]';
export const trpc = createTRPCNext<AppRouter>({
ssr: true,
ssrPrepass,
config(opts) {
const { ctx } = opts;
if (typeof window !== 'undefined') {
// during client requests
return {
links: [
httpBatchLink({
url: '/api/trpc',
}),
],
};
}
return {
links: [
httpBatchLink({
// The server needs to know your app's full url
url: `${getBaseUrl()}/api/trpc`,
/**
* Set custom request headers on every request from tRPC
* @link https://trpc.dokyumento.jp/docs/v10/header
*/
headers() {
if (!ctx?.req?.headers) {
return {};
}
// To use SSR properly, you need to forward client headers to the server
// This is so you can pass through things like cookies when we're server-side rendering
return {
cookie: ctx.req.headers.cookie,
};
},
}),
],
};
},
});
utils/trpc.ts
tsx
import { httpBatchLink } from '@trpc/client';
import { createTRPCNext } from '@trpc/next';
import { ssrPrepass } from '@trpc/next/ssrPrepass';
import superjson from 'superjson';
import type { AppRouter } from './api/trpc/[trpc]';
export const trpc = createTRPCNext<AppRouter>({
ssr: true,
ssrPrepass,
config(opts) {
const { ctx } = opts;
if (typeof window !== 'undefined') {
// during client requests
return {
links: [
httpBatchLink({
url: '/api/trpc',
}),
],
};
}
return {
links: [
httpBatchLink({
// The server needs to know your app's full url
url: `${getBaseUrl()}/api/trpc`,
/**
* Set custom request headers on every request from tRPC
* @link https://trpc.dokyumento.jp/docs/v10/header
*/
headers() {
if (!ctx?.req?.headers) {
return {};
}
// To use SSR properly, you need to forward client headers to the server
// This is so you can pass through things like cookies when we're server-side rendering
return {
cookie: ctx.req.headers.cookie,
};
},
}),
],
};
},
});

または、特定のリクエストに応じて SSR を条件付きで実行する場合は、ssr にコールバックを渡すことができます。このコールバックは、ブール値、またはブール値に解決される Promise を返すことができます

utils/trpc.ts
tsx
import { httpBatchLink } from '@trpc/client';
import { createTRPCNext } from '@trpc/next';
import superjson from 'superjson';
import type { AppRouter } from './api/trpc/[trpc]';
export const trpc = createTRPCNext<AppRouter>({
config(opts) {
const { ctx } = opts;
if (typeof window !== 'undefined') {
// during client requests
return {
links: [
httpBatchLink({
url: '/api/trpc',
}),
],
};
}
return {
links: [
httpBatchLink({
// The server needs to know your app's full url
url: `${getBaseUrl()}/api/trpc`,
/**
* Set custom request headers on every request from tRPC
* @link https://trpc.dokyumento.jp/docs/v10/header
*/
headers() {
if (!ctx?.req?.headers) {
return {};
}
// To use SSR properly, you need to forward client headers to the server
// This is so you can pass through things like cookies when we're server-side rendering
return {
cookie: ctx.req.headers.cookie,
};
},
}),
],
};
},
ssr(opts) {
// only SSR if the request is coming from a bot
return opts.ctx?.req?.headers['user-agent']?.includes('bot');
},
});
utils/trpc.ts
tsx
import { httpBatchLink } from '@trpc/client';
import { createTRPCNext } from '@trpc/next';
import superjson from 'superjson';
import type { AppRouter } from './api/trpc/[trpc]';
export const trpc = createTRPCNext<AppRouter>({
config(opts) {
const { ctx } = opts;
if (typeof window !== 'undefined') {
// during client requests
return {
links: [
httpBatchLink({
url: '/api/trpc',
}),
],
};
}
return {
links: [
httpBatchLink({
// The server needs to know your app's full url
url: `${getBaseUrl()}/api/trpc`,
/**
* Set custom request headers on every request from tRPC
* @link https://trpc.dokyumento.jp/docs/v10/header
*/
headers() {
if (!ctx?.req?.headers) {
return {};
}
// To use SSR properly, you need to forward client headers to the server
// This is so you can pass through things like cookies when we're server-side rendering
return {
cookie: ctx.req.headers.cookie,
};
},
}),
],
};
},
ssr(opts) {
// only SSR if the request is coming from a bot
return opts.ctx?.req?.headers['user-agent']?.includes('bot');
},
});
pages/_app.tsx
tsx
import { trpc } from '~/utils/trpc';
import type { AppProps } from 'next/app';
import React from 'react';
const MyApp: AppType = ({ Component, pageProps }: AppProps) => {
return <Component {...pageProps} />;
};
export default trpc.withTRPC(MyApp);
pages/_app.tsx
tsx
import { trpc } from '~/utils/trpc';
import type { AppProps } from 'next/app';
import React from 'react';
const MyApp: AppType = ({ Component, pageProps }: AppProps) => {
return <Component {...pageProps} />;
};
export default trpc.withTRPC(MyApp);

よくある質問

Q: クライアントのヘッダーをサーバーに手動で転送する必要があるのはなぜですか? tRPC が自動的にそれを行わないのはなぜですか?

SSR を実行する際にクライアントのヘッダーをサーバーに転送したくないことはまれですが、ヘッダーに動的に何かを追加したい場合があります。そのため、tRPC はヘッダーキーの衝突などの責任を負いません。

Q: Node 18 で SSR を使用する場合、なぜ connection ヘッダーを削除する必要があるのですか?

connection ヘッダーを削除しないと、connection禁止されているヘッダー名であるため、データの取得は TRPCClientError: fetch failed で失敗します。

Q: なぜネットワークタブでネットワークリクエストが fortfarande 行われているのが見えるのですか?

デフォルトでは、@tanstack/react-query (データ取得フックに使用しています) は、SSR 経由で初期データがすでに取得されている場合でも、マウント時とウィンドウの再フォーカス時にデータを再取得します。これにより、データは常に最新の状態になります。この動作を無効にする場合は、SSG のページを参照してください.