SPA-Modus

Was zum Teufel ist SPA-Modus?

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.

Warum Start ohne SSR verwenden?

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**.

Vorteile des SPA-Modus

  • Einfacher bereitzustellen - Ein CDN, das statische Assets bereitstellen kann, ist alles, was Sie brauchen.
  • Günstiger im Hosting - CDNs sind im Vergleich zu Lambda-Funktionen oder langlebigen Prozessen günstig.
  • Nur clientseitig ist einfacher - Kein SSR bedeutet weniger, was bei Hydration, Rendering und Routing schiefgehen kann.

Vorbehalte des SPA-Modus

  • Langsamere Zeit bis zum vollständigen Inhalt - Die Zeit bis zum vollständigen Inhalt ist länger, da alle JS heruntergeladen und ausgeführt werden müssen, bevor etwas unterhalb der Shell gerendert werden kann.
  • Weniger SEO-freundlich - Robots, Crawler und Link-Unfurlers *können* Schwierigkeiten haben, Ihre Anwendung zu indizieren, es sei denn, sie sind für die Ausführung von JS konfiguriert und Ihre Anwendung kann innerhalb einer angemessenen Zeit gerendert werden.

Wie funktioniert es?

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

  • Vorabrendern nur der Stammroute Ihrer Anwendung
  • Wo Ihre Anwendung normalerweise Ihre übereinstimmenden Routen rendern würde, wird stattdessen die konfigurierte **ausstehende Fallback-Komponente** Ihres Routers gerendert.
  • Das resultierende HTML wird in einer statischen HTML-Seite namens /_shell.html (konfigurierbar) gespeichert.
  • Standardmäßig sind Rewrites konfiguriert, um alle 404-Anfragen an die SPA-Modus-Shell weiterzuleiten.

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.

Konfigurieren des SPA-Modus

Um den SPA-Modus zu konfigurieren, gibt es einige Optionen, die Sie zu den Optionen Ihres Start-Plugins hinzufügen können.

tsx
// vite.config.ts
export default defineConfig({
  plugins: [
    TanStackStart({
      spa: {
        enabled: true,
      },
    }),
  ],
})
// vite.config.ts
export default defineConfig({
  plugins: [
    TanStackStart({
      spa: {
        enabled: true,
      },
    }),
  ],
})

Notwendige Weiterleitungen verwenden

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:

  1. Stellen Sie sicher, dass statische Assets immer bereitgestellt werden, wenn sie vorhanden sind, z. B. /about.html. Dies ist normalerweise das Standardverhalten für die meisten CDNs.
  2. (Optional) Erlauben Sie spezifische Unterpfade, die an dynamische Serverhandler weitergeleitet werden, z. B. /api/** (Mehr dazu unten).
  3. Stellen Sie sicher, dass alle 404-Anfragen an die SPA-Shell weitergeleitet werden, z. B. eine Catch-all-Weiterleitung zu /_shell.html (oder wenn Sie Ihren Shell-Ausgabepfad benutzerdefiniert konfiguriert haben, verwenden Sie diesen stattdessen).

Beispiel für einfache Weiterleitungen

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

Serverfunktionen und Serverrouten zulassen

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

Shell-Maskenpfad

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.

tsx
// vite.config.ts
export default defineConfig({
  plugins: [
    tanstackStart({
      spa: {
        maskPath: '/app',
      },
    }),
  ],
})
// vite.config.ts
export default defineConfig({
  plugins: [
    tanstackStart({
      spa: {
        maskPath: '/app',
      },
    }),
  ],
})

Optionen für das Vorabrendern

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:

  • outputPath: /_shell.html
  • crawlLinks: false
  • retryCount: 0

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.

tsx
// 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,
        },
      },
    }),
  ],
})

Benutzerdefinierte Wiedergabe im SPA-Modus

Die Anpassung der HTML-Ausgabe der SPA-Shell kann nützlich sein, wenn Sie Folgendes tun möchten:

  • Generische Head-Tags für SPA-Routen bereitstellen
  • Eine benutzerdefinierte ausstehende Fallback-Komponente bereitstellen
  • Buchstäblich alles am HTML, CSS und JS der Shell ändern

Um diesen Prozess zu vereinfachen, gibt es eine Funktion isShell(), die auf der router-Instanz zu finden ist.

tsx
// 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.**

Dynamische Daten in Ihrer Shell

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.

tsx
// 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>
  )
}
Unsere Partner
Code Rabbit
Netlify
Neon
Clerk
Convex
Sentry
Prisma
Bytes abonnieren

Ihre wöchentliche Dosis JavaScript-Nachrichten. Jeden Montag kostenlos an über 100.000 Entwickler geliefert.

Bytes

Kein Spam. Jederzeit kündbar.

Bytes abonnieren

Ihre wöchentliche Dosis JavaScript-Nachrichten. Jeden Montag kostenlos an über 100.000 Entwickler geliefert.

Bytes

Kein Spam. Jederzeit kündbar.