Warnung
Obwohl alle Anstrengungen unternommen wurden, um diese APIs von Änderungen an Tanstack Start zu trennen, gibt es intern zugrunde liegende gemeinsame Implementierungen. Daher können diese Änderungen unterworfen sein und sollten als experimentell betrachtet werden, bis Start den stabilen Status erreicht.
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 Varianten von SSR, die in Betracht gezogen werden sollten
Diese Anleitung erklärt, wie beide Varianten von SSR 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 der Daten) an den Client. Der Client hydriert dann das Markup wieder zu einer voll interaktiven Anwendung.
Um nicht-streaming SSR mit TanStack Router zu implementieren, benötigen Sie die folgenden Hilfsmittel
Auf dem Client verwendet Router standardmäßig eine Instanz von createBrowserHistory, was der bevorzugte Verlaufstyp für den 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 Loader-Daten werden von TanStack Router automatisch dehydriert und rehydriert, solange Sie die Standard-SSR-Schritte abschließen, die in dieser Anleitung beschrieben sind.
⚠️ Wenn Sie Deferred Data Streaming verwenden, müssen Sie auch sicherstellen, dass Sie das Muster SSR Streaming & Stream Transform am Ende dieser Anleitung implementiert haben.
Weitere Informationen zur Verwendung von Datenladung finden Sie in der Anleitung Data Loading.
Da Ihr Router sowohl auf dem Server als auch auf dem Client existiert, ist es wichtig, dass Sie Ihren Router so erstellen, dass er in beiden Umgebungen konsistent ist. Der einfachste Weg, dies zu tun, ist die Bereitstellung einer createRouter-Funktion in einer gemeinsamen Datei, die sowohl von Ihrem Server- als auch von Ihrem Client-Eintragsdateien importiert und aufgerufen werden kann.
// src/router.tsx
import { createRouter as createTanstackRouter } from '@tanstack/solid-router'
import { routeTree } from './routeTree.gen'
export function createRouter() {
return createTanstackRouter({ routeTree })
}
declare module '@tanstack/solid-router' {
interface Register {
router: ReturnType<typeof createRouter>
}
}
// src/router.tsx
import { createRouter as createTanstackRouter } from '@tanstack/solid-router'
import { routeTree } from './routeTree.gen'
export function createRouter() {
return createTanstackRouter({ routeTree })
}
declare module '@tanstack/solid-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/solid-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/solid-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/solid-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/solid-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 erfordert ein Standard-Request-Objekt der Web-API, während die Handler-Methode ein Standard-Response-Promise der Web-API 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. Schauen Sie sich die Beispiele an, wie eine solche Implementierung aussehen könnte.
Auf dem Client ist alles viel einfacher.
// src/entry-client.tsx
import { hydrate } from 'solid-js/web'
import { RouterClient } from '@tanstack/solid-router/ssr/client'
import { createRouter } from './router'
const router = createRouter()
hydrate(() => <RouterClient router={router} />, document.body)
// src/entry-client.tsx
import { hydrate } from 'solid-js/web'
import { RouterClient } from '@tanstack/solid-router/ssr/client'
import { createRouter } from './router'
const router = createRouter()
hydrate(() => <RouterClient router={router} />, document.body)
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 des kontinuierlichen und inkrementellen Sendens von HTML-Markup an den Client, während es auf dem Server gerendert wird. Dies unterscheidet sich konzeptionell leicht vom traditionellen SSR, da über die Fähigkeit hinaus, einen kritischen ersten Farbanstrich, Markup und Daten mit geringerer Priorität oder langsamerer Antwortzeit zu dehydrieren und zu rehydrieren, Markup und Daten nach dem anfänglichen Rendern, aber innerhalb derselben Anfrage, an den Client gestreamt werden können.
Dieses Muster kann für Seiten nützlich sein, die langsame oder latenzintensive Datenabrufanforderungen haben. Wenn Sie beispielsweise eine Seite haben, die Daten von einer Drittanbieter-API abrufen muss, können Sie das kritische anfängliche Markup und die Daten an den Client streamen und dann die weniger kritischen Drittanbieterdaten an den Client streamen, sobald sie aufgelöst sind.
Hinweis
Dieses Streaming-Muster ist vollständig automatisch, solange Sie entweder defaultStreamHandler oder renderRouterToStream verwenden.
mit defaultStreamHandler
// src/entry-server.tsx
import {
createRequestHandler,
defaultStreamHandler,
} from '@tanstack/solid-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/solid-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/solid-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/solid-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 Markup hinausgeht und es Ihnen ermöglicht, beliebige unterstützende Daten vom Server zum Client zu dehydrieren und zu streamen und sie bei Ankunft zu rehydrieren. Dies ist nützlich für Anwendungen, die möglicherweise die zugrunde liegenden Daten, die zum Rendern des anfänglichen 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 weitere Typen standardmäßig unterstützt werden sollten, eröffnen Sie bitte ein Issue im TanStack Router Repository.
Wenn Sie komplexere Datentypen wie Map, Set, BigInt usw. verwenden, benötigen Sie möglicherweise einen benutzerdefinierten Serialisierer, um sicherzustellen, dass Ihre Typdefinitionen korrekt sind und Ihre Daten richtig serialisiert und deserialisiert werden. Wir arbeiten derzeit an einem robusteren Serialisierer und einer Möglichkeit, den Serialisierer für Ihre Anwendung anzupassen. Eröffnen Sie ein Issue, wenn Sie daran interessiert sind, zu helfen!
Ihre wöchentliche Dosis JavaScript-Nachrichten. Jeden Montag kostenlos an über 100.000 Entwickler geliefert.