Für Anwendungen, die kein SSR für SEO-, Crawler- oder Performance-Zwecke benötigen, kann es wünschenswert sein, statisches HTML an Ihre Benutzer zu liefern, das die "Shell" Ihrer Anwendung enthält (oder sogar vorab gerendertes HTML für bestimmte Routen), das die notwendigen html-, head- und body-Tags enthält, um Ihre Anwendung nur auf dem Client zu starten.
Kein SSR bedeutet nicht, auf serverseitige Funktionen zu verzichten! SPA-Modi lassen sich tatsächlich sehr gut mit serverseitigen Funktionen wie Serverfunktionen und/oder Serverrouten oder sogar anderen externen APIs kombinieren. Es bedeutet **lediglich, dass das anfängliche Dokument nicht das vollständig gerenderte HTML Ihrer Anwendung enthält, bis es auf dem Client mit JavaScript gerendert wurde**.
Nachdem der SPA-Modus aktiviert wurde, wird ein Start-Build danach einen zusätzlichen Vorabrender-Schritt ausführen, um die Shell zu generieren. Dies geschieht durch
Hinweis
Andere Routen können ebenfalls vorab gerendert werden, und es wird empfohlen, im SPA-Modus so viel wie möglich vorab zu rendern, dies ist jedoch nicht erforderlich, damit der SPA-Modus funktioniert.
Um den SPA-Modus zu konfigurieren, gibt es einige Optionen, die Sie zu den Optionen Ihres Start-Plugins hinzufügen können.
// vite.config.ts
export default defineConfig({
plugins: [
TanStackStart({
spa: {
enabled: true,
},
}),
],
})
// vite.config.ts
export default defineConfig({
plugins: [
TanStackStart({
spa: {
enabled: true,
},
}),
],
})
Das Bereitstellen einer rein clientseitigen SPA auf einem Host oder CDN erfordert oft die Verwendung von Weiterleitungen, um sicherzustellen, dass URLs ordnungsgemäß zur SPA-Shell umgeschrieben werden. Das Ziel jeder Bereitstellung sollte diese Prioritäten in dieser Reihenfolge beinhalten:
Verwenden wir die _redirects-Datei von Netlify, um alle 404-Anfragen an die SPA-Shell umzuschreiben.
# Catch all other 404 requests and rewrite them to the SPA shell
/* /_shell.html 200
# Catch all other 404 requests and rewrite them to the SPA shell
/* /_shell.html 200
Wiederum können wir mit der _redirects-Datei von Netlify spezifische Unterpfade erlauben, die an den Server weitergeleitet werden.
# Allow requests to /_serverFn/* to be routed through to the server (If you have configured your server function base path to be something other than /_serverFn, use that instead)
/_serverFn/* /_serverFn/:splat 200
# Allow any requests to /api/* to be routed through to the server (Server routes can be created at any path, so you must ensure that any server routes you want to use are under this path, or simply add additional redirects for each server route base you want to expose)
/api/* /api/:splat 200
# Catch all other 404 requests and rewrite them to the SPA shell
/* /_shell.html 200
# Allow requests to /_serverFn/* to be routed through to the server (If you have configured your server function base path to be something other than /_serverFn, use that instead)
/_serverFn/* /_serverFn/:splat 200
# Allow any requests to /api/* to be routed through to the server (Server routes can be created at any path, so you must ensure that any server routes you want to use are under this path, or simply add additional redirects for each server route base you want to expose)
/api/* /api/:splat 200
# Catch all other 404 requests and rewrite them to the SPA shell
/* /_shell.html 200
Der Standardpfadname, der zur Generierung der SPA-Shell verwendet wird, ist /. Wir nennen dies den **Shell-Maskenpfad**. Da übereinstimmende Routen nicht enthalten sind, ist der Pfadname, der zur Generierung der Shell verwendet wird, weitgehend irrelevant, aber er ist dennoch konfigurierbar.
Hinweis
Es wird empfohlen, den Standardwert von / als Shell-Maskenpfad beizubehalten.
// vite.config.ts
export default defineConfig({
plugins: [
tanstackStart({
spa: {
maskPath: '/app',
},
}),
],
})
// vite.config.ts
export default defineConfig({
plugins: [
tanstackStart({
spa: {
maskPath: '/app',
},
}),
],
})
Die Option `prerender` wird verwendet, um das Vorabrender-Verhalten der SPA-Shell zu konfigurieren, und akzeptiert dieselben `prerender`-Optionen wie in unserem Leitfaden zum Vorabrendern beschrieben.
Standardmäßig werden die folgenden prerender-Optionen gesetzt:
Das bedeutet, dass die Shell standardmäßig nicht nach Links durchsucht wird, um zusätzliche Vorabrenderungen zu verfolgen, und fehlgeschlagene Vorabrenderungen nicht wiederholt werden.
Sie können diese Optionen jederzeit überschreiben, indem Sie Ihre eigenen `prerender`-Optionen angeben.
// vite.config.ts
export default defineConfig({
plugins: [
TanStackStart({
spa: {
prerender: {
outputPath: '/custom-shell',
crawlLinks: true,
retryCount: 3,
},
},
}),
],
})
// vite.config.ts
export default defineConfig({
plugins: [
TanStackStart({
spa: {
prerender: {
outputPath: '/custom-shell',
crawlLinks: true,
retryCount: 3,
},
},
}),
],
})
Die Anpassung der HTML-Ausgabe der SPA-Shell kann nützlich sein, wenn Sie Folgendes tun möchten:
Um diesen Prozess zu vereinfachen, gibt es eine Funktion isShell(), die auf der router-Instanz zu finden ist.
// src/routes/root.tsx
export default function Root() {
const isShell = useRouter().isShell()
if (isShell) console.log('Rendering the shell!')
}
// src/routes/root.tsx
export default function Root() {
const isShell = useRouter().isShell()
if (isShell) console.log('Rendering the shell!')
}
Sie können diesen booleschen Wert verwenden, um bedingt unterschiedliche Benutzeroberflächen zu rendern, je nachdem, ob die aktuelle Route eine Shell ist oder nicht. Beachten Sie jedoch, dass der Router nach dem Hydrieren der Shell sofort zur ersten Route navigiert und isShell() false zurückgibt. **Dies könnte zu flackernden ungestylten Inhalten führen, wenn es nicht ordnungsgemäß gehandhabt wird.**
Da die Shell mit dem SSR-Build Ihrer Anwendung vorab gerendert wird, werden alle loader oder serverseitigen Funktionalitäten, die auf Ihrer **Stammroute** definiert sind, während des Vorabrender-Prozesses ausgeführt und die Daten werden in die Shell aufgenommen.
Das bedeutet, dass Sie dynamische Daten in Ihrer Shell verwenden können, indem Sie einen loader oder serverseitige Funktionalitäten verwenden.
// src/routes/__root.tsx
export const RootRoute = createRootRoute({
loader: async () => {
return {
name: 'Tanner',
}
},
component: Root,
})
export default function Root() {
const { name } = useLoaderData()
return (
<html>
<body>
<h1>Hello, {name}!</h1>
<Outlet />
</body>
</html>
)
}
// src/routes/__root.tsx
export const RootRoute = createRootRoute({
loader: async () => {
return {
name: 'Tanner',
}
},
component: Root,
})
export default function Root() {
const { name } = useLoaderData()
return (
<html>
<body>
<h1>Hello, {name}!</h1>
<Outlet />
</body>
</html>
)
}
Ihre wöchentliche Dosis JavaScript-Nachrichten. Jeden Montag kostenlos an über 100.000 Entwickler geliefert.