Warnung
Obwohl alle Anstrengungen unternommen wurden, um diese APIs von Änderungen an Tanstack Start zu trennen, gibt es intern zugrundeliegende gemeinsame Implementierungen. Daher können diese Änderungen unterliegen und bis zum stabilen Status von Start als experimentell betrachtet werden.
Server Side Rendering (SSR) ist der Prozess des Renderns einer Komponente auf dem Server und des Sendens des HTML-Markups an den Client. Der Client hydriert dann das Markup zu einer vollständig interaktiven Komponente.
Es gibt normalerweise zwei verschiedene Geschmacksrichtungen von SSR zu beachten
Diese Anleitung erklärt, wie beide SSR-Varianten mit TanStack Router implementiert werden!
Nicht-Streaming Server-Side Rendering ist der klassische Prozess des Renderns des Markups für Ihre gesamte Anwendungsseite auf dem Server und des Sendens des fertigen HTML-Markups (und Daten) an den Client. Der Client hydriert dann das Markup erneut zu einer voll interaktiven Anwendung.
Um Nicht-Streaming SSR mit TanStack Router zu implementieren, benötigen Sie die folgenden Hilfsprogramme
Auf dem Client verwendet Router standardmäßig eine Instanz von createBrowserHistory, was der bevorzugte Verlaufstyp für die Verwendung auf dem Client ist. Auf dem Server möchten Sie stattdessen eine Instanz von createMemoryHistory verwenden. Dies liegt daran, dass createBrowserHistory das window Objekt verwendet, das auf dem Server nicht existiert. Dies wird für Sie in der RouterServer-Komponente automatisch gehandhabt.
Von Routen abgerufene Ladeinhalte werden von TanStack Router automatisch dehydriert und rehydriert, solange Sie die Standard-SSR-Schritte dieser Anleitung befolgen.
⚠️ Wenn Sie Deferred Data Streaming verwenden, müssen Sie außerdem sicherstellen, dass Sie das SSR-Streaming- & Stream-Transform-Muster am Ende dieser Anleitung implementiert haben.
Weitere Informationen zur Verwendung von Datenladungen finden Sie in der Anleitung zur Datenladung.
Da Ihr Router sowohl auf dem Server als auch auf dem Client existieren wird, ist es wichtig, dass Sie Ihren Router so erstellen, dass er zwischen beiden Umgebungen konsistent ist. Der einfachste Weg, dies zu tun, ist, eine createRouter Funktion in einer gemeinsamen Datei bereitzustellen, die sowohl von Ihrem Server- als auch von Ihrem Client-Eintrag importiert und aufgerufen werden kann.
// src/router.tsx
import { createRouter as createTanstackRouter } from '@tanstack/react-router'
import { routeTree } from './routeTree.gen'
export function createRouter() {
return createTanstackRouter({ routeTree })
}
declare module '@tanstack/react-router' {
interface Register {
router: ReturnType<typeof createRouter>
}
}
// src/router.tsx
import { createRouter as createTanstackRouter } from '@tanstack/react-router'
import { routeTree } from './routeTree.gen'
export function createRouter() {
return createTanstackRouter({ routeTree })
}
declare module '@tanstack/react-router' {
interface Register {
router: ReturnType<typeof createRouter>
}
}
Nun, da Sie eine Router-Instanz haben, die alle kritischen Daten für die aktuelle URL geladen hat, können Sie Ihre Anwendung auf dem Server rendern
mit defaultRenderToString
// src/entry-server.tsx
import {
createRequestHandler,
defaultRenderToString,
} from '@tanstack/react-router/ssr/server'
import { createRouter } from './router'
export async function render({ request }: { request: Request }) {
const handler = createRequestHandler({ request, createRouter })
return await handler(defaultRenderToString)
}
// src/entry-server.tsx
import {
createRequestHandler,
defaultRenderToString,
} from '@tanstack/react-router/ssr/server'
import { createRouter } from './router'
export async function render({ request }: { request: Request }) {
const handler = createRequestHandler({ request, createRouter })
return await handler(defaultRenderToString)
}
mit renderRouterToString
// src/entry-server.tsx
import {
createRequestHandler,
renderRouterToString,
RouterServer,
} from '@tanstack/react-router/ssr/server'
import { createRouter } from './router'
export function render({ request }: { request: Request }) {
const handler = createRequestHandler({ request, createRouter })
return handler(({ request, responseHeaders, router }) =>
renderRouterToString({
request,
responseHeaders,
router,
children: <RouterServer router={router} />,
}),
)
}
// src/entry-server.tsx
import {
createRequestHandler,
renderRouterToString,
RouterServer,
} from '@tanstack/react-router/ssr/server'
import { createRouter } from './router'
export function render({ request }: { request: Request }) {
const handler = createRequestHandler({ request, createRouter })
return handler(({ request, responseHeaders, router }) =>
renderRouterToString({
request,
responseHeaders,
router,
children: <RouterServer router={router} />,
}),
)
}
HINWEIS: Die Methode createRequestHandler benötigt ein Web-API-Standard-Request-Objekt, während die Handler-Methode ein Web-API-Standard-Response-Promise zurückgibt.
Wenn Sie ein Server-Framework wie Express verwenden, das seine eigenen Request- und Response-Objekte verwendet, müssten Sie vom einen zum anderen konvertieren. Bitte schauen Sie sich die Beispiele an, wie eine solche Implementierung aussehen könnte.
Auf dem Client ist die Sache viel einfacher.
// src/entry-client.tsx
import { hydrateRoot } from 'react-dom/client'
import { RouterClient } from '@tanstack/react-router/ssr/client'
import { createRouter } from './router'
const router = createRouter()
hydrateRoot(document, <RouterClient router={router} />)
// src/entry-client.tsx
import { hydrateRoot } from 'react-dom/client'
import { RouterClient } from '@tanstack/react-router/ssr/client'
import { createRouter } from './router'
const router = createRouter()
hydrateRoot(document, <RouterClient router={router} />)
Mit dieser Einrichtung wird Ihre Anwendung auf dem Server gerendert und dann auf dem Client hydriert!
Streaming SSR ist die modernste Variante von SSR und ist der Prozess, kontinuierlich und inkrementell HTML-Markup an den Client zu senden, während es auf dem Server gerendert wird. Dies unterscheidet sich leicht vom traditionellen SSR, da über die Möglichkeit, eine kritische erste Darstellung, Markup und Daten mit geringerer Priorität oder langsameren Antwortzeiten zu dehydrieren und zu rehydrieren, hinaus, Markup und Daten nach dem initialen Rendern, aber in derselben Anfrage, an den Client gestreamt werden können.
Dieses Muster kann nützlich sein für Seiten mit langsamen oder hochlatenzabhängigen Datenanforderungen. Wenn Sie beispielsweise eine Seite haben, die Daten von einer Drittanbieter-API abrufen muss, können Sie das kritische initiale Markup und die Daten an den Client streamen und dann die weniger kritischen Drittanbieter-Daten an den Client streamen, sobald sie aufgelöst sind.
Hinweis
Dieses Streaming-Muster ist vollautomatisch, solange Sie entweder defaultStreamHandler oder renderRouterToStream verwenden.
mit defaultStreamHandler
// src/entry-server.tsx
import {
createRequestHandler,
defaultStreamHandler,
} from '@tanstack/react-router/ssr/server'
import { createRouter } from './router'
export async function render({ request }: { request: Request }) {
const handler = createRequestHandler({ request, createRouter })
return await handler(defaultStreamHandler)
}
// src/entry-server.tsx
import {
createRequestHandler,
defaultStreamHandler,
} from '@tanstack/react-router/ssr/server'
import { createRouter } from './router'
export async function render({ request }: { request: Request }) {
const handler = createRequestHandler({ request, createRouter })
return await handler(defaultStreamHandler)
}
mit renderRouterToStream
// src/entry-server.tsx
import {
createRequestHandler,
renderRouterToStream,
RouterServer,
} from '@tanstack/react-router/ssr/server'
import { createRouter } from './router'
export function render({ request }: { request: Request }) {
const handler = createRequestHandler({ request, createRouter })
return handler(({ request, responseHeaders, router }) =>
renderRouterToStream({
request,
responseHeaders,
router,
children: <RouterServer router={router} />,
}),
)
}
// src/entry-server.tsx
import {
createRequestHandler,
renderRouterToStream,
RouterServer,
} from '@tanstack/react-router/ssr/server'
import { createRouter } from './router'
export function render({ request }: { request: Request }) {
const handler = createRequestHandler({ request, createRouter })
return handler(({ request, responseHeaders, router }) =>
renderRouterToStream({
request,
responseHeaders,
router,
children: <RouterServer router={router} />,
}),
)
}
Streaming-Dehydrierung/Hydrierung ist ein fortgeschrittenes Muster, das über das Markup hinausgeht und es Ihnen ermöglicht, beliebige unterstützende Daten vom Server zum Client zu dehydrieren und zu streamen und sie bei Ankunft wieder zu hydrieren. Dies ist nützlich für Anwendungen, die die zugrundeliegenden Daten, die zum Rendern des initialen Markups auf dem Server verwendet wurden, weiter verwenden/verwalten müssen.
Bei Verwendung von SSR müssen Daten, die zwischen Server und Client übergeben werden, serialisiert werden, bevor sie über Netzwerkgrenzen hinweg gesendet werden. TanStack Router handhabt diese Serialisierung mit einem sehr leichten Serialisierer, der gängige Datentypen über JSON.stringify/JSON.parse hinaus unterstützt.
Standardmäßig werden die folgenden Typen unterstützt
Wenn Sie der Meinung sind, dass andere Typen standardmäßig unterstützt werden sollten, eröffnen Sie bitte ein Problem im TanStack Router Repository.
Wenn Sie komplexere Datentypen wie Map, Set, BigInt usw. verwenden, müssen Sie möglicherweise einen benutzerdefinierten Serialisierer verwenden, um sicherzustellen, dass Ihre Typdefinitionen korrekt sind und Ihre Daten richtig serialisiert und deserialisiert werden. Wir arbeiten derzeit sowohl an einem robusteren Serialisierer als auch an einer Möglichkeit, den Serialisierer für Ihre Anwendung anzupassen. Eröffnen Sie ein Problem, wenn Sie daran interessiert sind zu helfen!
Ihre wöchentliche Dosis JavaScript-Nachrichten. Jeden Montag kostenlos an über 100.000 Entwickler geliefert.