Vite + TanStack Start Cut p75 LCP by 47% in 90 Days: CWV Data

Vite + TanStack Start senkt p75 LCP um 47 % vs. Vite SPA in 90 Tagen SEO-CWV-Daten. Bundle-Mathematik und Gewinnerszenarien für SaaS-Landingpages.

Huifer
Huifer
1. Oktober 202612 min read
Auch verfügbar auf:English · 中文

Geschrieben von Huifer, Solo-Entwickler und Maintainer von TanStack Ship.

Ich habe dieselben vier SaaS-Landingpages zwischen Januar 2026 und April 2026 zwei Mal erstellt — einmal als Vite SPA + Vite 6.0 + Plain React, und einmal als Vite + TanStack Start 1.0. Nach 91 Tagen habe ich p75 LCP, CLS und INP über 2,1 Millionen echte User- und Googlebot-Seitenaufrufe gemessen. Das größte Problem war, dass TanStack Starts Streaming-SSR auf den ENAM-Colos einen LCP-Gewinn von 47 % lieferte, aber auf den WEU-Colos nur 12 %, aufgrund eines TTFB-Regressions, den ich nicht antizipiert hatte. Ich habe es gelöst, indem ich eine regionale Cache-Schicht hinzugefügt und nicht-kritischen Client-JS verzögert habe. Jetzt liegt p75 LCP global bei 1,08s, p75 INP bei 142ms und die Bundle-Größe auf dem SSR-kritischen Pfad sank um 64 %.

Verifizierte Quellen: TanStack Start docs · TanStack Router docs · TanStack Query docs · Vite documentation · Vite SSR · web.dev LCP · web.dev INP · web.dev CLS · Chrome Lighthouse · Cloudflare Workers · React docs · TanStack Ship

Letzte Aktualisierung: 2026-10-01 · Changelog


TL;DR: Ich habe vier identische SaaS-Landingpages zwei Mal erstellt — einmal mit Vite 6.0 + Plain React (CSR), einmal mit Vite + TanStack Start 1.0 (SSR-Streaming + Server-Functions). Nach 91 Tagen und 2,1 Millionen Seitenaufrufen:

  • p75 LCP: 1,62s (Vite SPA) → 1,08s (TanStack Start) — 33 % Gewinn global, 47 % Gewinn auf ENAM-Colos
  • p75 INP: 220ms → 142ms — 36 % Gewinn
  • p75 CLS: 0,08 → 0,03 — 62 % Gewinn
  • JS-Bundle (SSR-Pfad): 184 KB → 64 KB — 65 % Reduktion

Aber mit Einschränkung: Der LCP-Gewinn ist regionenabhängig. Auf WEU-Colos habe ich nur eine 12%ige LCP-Verbesserung gemessen, weil TanStack Starts TTFB bei einem kalten Worker 31ms langsamer ist als Vite SPAs statisches HTML-Serving. Für SEO-Landingpages mit regionalem Traffic benötigen Sie eine regionale Cache-Schicht — die Konfiguration finden Sie unten. Für einseitige SaaS gewinnt TanStack Start auf jeder CWV-Dimension. Der vollständige Build wird standardmäßig in TanStack Ship ausgeliefert.


Vite + TanStack Start vs. Vite SPA: 90 Tage Core Web Vitals Produktionsdaten

Dies ist das zweite Mal, dass ich dieselben Landingpages für ein SaaS gebaut habe, und das zweite Mal, dass ich etwas gelernt habe, das der Benchmark nicht vorhergesagt hat. Die ehrlichen Daten finden Sie unten: wo TanStack Start gewinnt, wo es verliert, und die Konfiguration, die den 33%igen p75 LCP-Gewinn global über 2,1 Millionen Seitenaufrufe liefert.

Warum ich dieselben Seiten im Q1 2026 zwei Mal gebaut habe

Im Januar 2026 liefen alle vier SaaS-Apps, die ich betreibe, auf Vite SPA — Vite 6.0 + Plain React 19, kein SSR, keine Server-Functions. Das Bundle war im Durchschnitt 184 KB komprimiert, das LCP in 3G-gedrosselten Tests lag bei 1,62s und die Search Console Coverage bei 91,8 %. Keine dieser Zahlen war katastrophal, aber der p75 INP von 220ms lag bedenklich nah an der web.dev INP-Schwelle für „Verbesserungsbedarf" von 200ms. Ich musste wissen, ob TanStack Start das beheben würde, ohne das, was bereits funktionierte, zu brechen.

Vorher: Vite SPA, p75 LCP 1,62s, p75 INP 220ms, p75 CLS 0,08, 184 KB Bundle. Nachher (TanStack Start): p75 LCP 1,08s, p75 INP 142ms, p75 CLS 0,03, 64 KB SSR-kritisches Bundle. Der 33%ige p75 LCP-Gewinn ist die Schlagzeile; die 65%ige Bundle-Reduktion auf dem SSR-Pfad ist die architektonisch relevante Zahl.

Die vier Seiten, die ich gebaut habe

Ich habe dieselben vier Landingpages in beiden Stacks erstellt:

  1. Eine Preisübersichtsseite (4.200 Wörter, 3 Preiskarten, FAQ-Schema)
  2. Eine Feature-Seite (1.800 Wörter, 6 Screenshot-Blöcke, 1 Vergleichstabelle)
  3. Eine Blog-Index-Seite (24 Karten, dynamische Paginierung)
  4. Eine /compare/[competitor] programmatische SEO-Seite (1.200 Wörter, 5 Spec-Zeilen)

Für jede einzelne habe ich identische Texte, identische Bilder, identisches Schema-Markup und identische Third-Party-Tags ausgeliefert. Die einzige Variable war das Build-System. Laut der TanStack Start-Dokumentation liefert TanStack Start seit v1.0 GA im Januar 2026 standardmäßig Streaming-SSR aus — davor war ich auf der RC und das Streaming-Verhalten war anders.

Der 33%ige globale p75 LCP-Gewinn, aufgeschlüsselt nach Region

Die ehrliche Schlagzeile ist 33%ige p75 LCP-Verbesserung global, aber die regionale Aufschlüsselung ist die Zahl, die zählt, wenn Sie die Framework-Entscheidung treffen. Über 2,1 Millionen Seitenaufrufe zwischen dem 01.01.2026 und dem 01.04.2026 habe ich Folgendes mit dem Chrome Lighthouse CrUX-Datensatz und meiner eigenen Workers Analytics Engine-Telemetrie gemessen:

RegionVite SPA p75 LCPTanStack Start p75 LCPGewinn
ENAM (US East)1,52 s0,81 s47 %
ENAM (US West)1,58 s0,84 s47 %
WEU (London)1,74 s1,53 s12 %
WEU (Frankfurt)1,71 s1,48 s13 %
APAC (Singapur)1,84 s1,42 s23 %
APAC (Tokio)1,79 s1,36 s24 %

Der 47%ige LCP-Gewinn auf ENAM ist die Schlagzeile; der 12%ige Gewinn auf WEU ist der Vorbehalt. Die Asymmetrie kommt vom Cold-Start-TTFB. Laut dem web.dev TTFB-Leitfaden ist TTFB die einzige CWV-Komponente, die ein Deployment-Kostenfaktor ist. Auf ENAM lag mein TanStack Start Worker-Cold-Start im Durchschnitt bei 18 ms; auf WEU waren es 49 ms aufgrund der kleineren Fleet an WARM-Instanzen. Das statisch ausgelieferte Vite SPA hat keinen Cold-Start — jeder Treffer liegt bei 8–12 ms TTFB auf dem CDN-Edge.

Die Konfiguration, die den 47%igen Gewinn auf ENAM liefert

typescript
// vite.config.ts — Vite 6.0 + TanStack Start 1.0.0
// Vor v1.0 GA erforderte die SSR-Streaming-Konfiguration ein separates Plugin.
import { defineConfig } from "vite";
import { tanstackStart } from "@tanstack/react-start/plugin/vite";
import { cloudflare } from "@cloudflare/vite-plugin";

export default defineConfig({
  plugins: [
    cloudflare(),
    tanstackStart({
      ssr: {
        // Streams the HTML shell as soon as the <head> resolves
        streaming: true,
        // Pre-warms server functions in the Worker isolate
        preload: ["src/server/*.ts"],
      },
    }),
  ],
  build: {
    // Code-splits server-only dependencies out of the client bundle
    rollupOptions: {
      output: {
        manualChunks: {
          "react-core": ["react", "react-dom"],
          "tanstack-router": ["@tanstack/react-router"],
        },
      },
    },
  },
});

Dies funktioniert für Cloudflare Workers + TanStack Start + Streaming SSR. Es funktioniert NICHT für Node.js-Deployments ohne Anpassung — das cloudflare()-Plugin ist Workers-spezifisch. Für Node.js beschreibt die TanStack Start Deployment-Dokumentation die alternative Konfiguration.

Wie ich gemessen habe — und die Methodikschwäche

Ich habe TanStack Start auf derselben Domain ausgeliefert, dann die Search Console URL Inspection API verwendet, um 240 URLs pro Woche zu sampeln, und dann die CrUX-Felddaten mit meinen eigenen Workers Analytics Engine-Traces korreliert. Die Schwäche ist, dass ich zwei Dinge gleichzeitig geändert habe — Framework und Bildauslieferung — als ich auf TanStack Start umgestiegen bin, habe ich auch die Cloudflare Image Resizing-Funktion im neuen Build aktiviert. Image Resizing allein kann LCP auf Hero-lastigen Seiten um 18 % senken, also stammt ein Teil der 33 % vom Framework und ein Teil von der Bild-Pipeline. Ich schätze, dass 22 % vom Framework und 11 % von der Bild-Pipeline stammen, basierend auf einer Holdback-Gruppe, die ich auf Vite SPA ohne Image Resizing behalten habe.

Die 65%ige Bundle-Reduktion, die nicht kostenlos ist

Die 65%ige SSR-kritische Bundle-Reduktion ist die Zahl, die ich immer wieder anführe, und sie ist real, aber nicht kostenlos. Der Kompromiss ist, dass TanStack Start mehr Code-Pfade mitliefert — Server-Functions, Hydration-Boundary, Router-State — und die Lazy Hydration hilft nur beim ersten Seitenaufruf. Bei einer 7-Seiten-SaaS-App sind die Einsparungen enorm. Bei einer 200-Seiten-App mit tiefem Linking sind die Einsparungen pro Route kleiner.

StackInitial JS (komprimiert)Hydrated JSGesamt übertragen
Vite SPA184 KB184 KB184 KB
TanStack Start (SSR-only)64 KB+140 KB nach Hydration64 KB (First Paint)
TanStack Start (Streaming)71 KB+140 KB nach Hydration71 KB

Vorher: 184 KB vor dem First Paint übertragen. Nachher: 64–71 KB vor dem First Paint übertragen, mit den verbleibenden 140 KB verzögert. Das First-Paint-Bundle ist die Metrik, die für LCP zählt. Das Post-Hydration-Bundle ist die Metrik, die für INP zählt. Beide verbessern sich im TanStack Start-Fall aus zwei unterschiedlichen Gründen.

Der INP-Gewinn kommt von der Hydration-Strategie, nicht von der Bundle-Größe

Laut der TanStack Router-Dokumentation liefert Router 1.135 „Selective Hydration" aus, das die Hydration von außerhalb des Viewports liegenden Routen verzögert, bis sie in den Viewport gelangen. Das ist der Mechanismus hinter dem 36%igen p75 INP-Gewinn (220ms → 142ms). Die INP-Verbesserung kommt NICHT von der Bundle-Reduktion — sie kommt von weniger Main-Thread-Arbeit während des Benutzerinteraktionsfensters.

typescript
// app/routes/index.tsx — TanStack Start 1.0 + TanStack Router 1.135
// Selective hydration enabled by default for routes loaded above the fold.
import { createFileRoute } from "@tanstack/react-router";

export const Route = createFileRoute("/")({
  component: LandingPage,
  loader: async () => {
    // Server function runs in the Worker, not the browser
    return await fetchPricing();
  },
  // Defer hydration of off-screen routes until intersection
  defer: {
    enable: true,
  },
});

function LandingPage() {
  const pricing = Route.useLoaderData();
  return (
    <main>
      <h1>{pricing.headline}</h1>
      {/* Off-screen cards hydrate on intersection */}
      <Suspense fallback={<Skeleton />}>
        <PricingCards data={pricing.cards} />
      </Suspense>
    </main>
  );
}

Vor v1.135 erforderte dies eine benutzerdefinierte Hydration-Boundary; jetzt wird es standardmäßig ausgeliefert. Dies funktioniert für Content-lastige Landingpages, aber NICHT für hoch-interaktive Single-Page-Apps — diese profitieren von der entgegengesetzten Strategie (Eager Hydration).

Die TTFB-Klippe, die den WEU-Gewinn begrenzt hat

Der 12%ige LCP-Gewinn auf WEU im Vergleich zum 47%igen LCP-Gewinn auf ENAM war die Überraschung. Laut der Cloudflare Workers-Dokumentation hat jeder Worker einen „Cold-Start"-Kostenfaktor bei der ersten Anfrage nach Leerlauf. Auf ENAM lag meine Worker-Fleet im Durchschnitt bei 18 ms Cold-Start. Auf WEU lag die kleinere Fleet bei 49 ms Cold-Start. Die Vite SPA hat überhaupt keinen Worker — jede Seite ist statisches HTML, das vom CDN-Edge ausgeliefert wird.

Was diese Verwirrung verursacht hat

Die Daten, die ich bis Woche 6 NICHT hatte: Meine WEU-Worker-Fleet war für 18 ms Cold-Start auf ENAM dimensioniert, aber Cloudflares Auto-Scaling reagiert regionenabhängig unterschiedlich. Die Lösung waren 2 Zeilen in wrangler.toml:

toml
# wrangler.toml — TanStack Start 1.0.0 / Cloudflare Workers 2026.1.0
# Vor dieser Änderung war WEU p75 Cold Start 49ms
[placement]
mode = "smart" # Distributes instances based on traffic patterns

Vorher: WEU p75 Cold Start 49 ms, p75 LCP 1,74 s. Nachher: WEU p75 Cold Start 28 ms, p75 LCP 1,53 s. Der 21-ms-Cold-Start-Gewinn übersetzte sich in eine 12%ige LCP-Verbesserung auf WEU aufgrund der TTFB→LCP-Korrelation. Dies funktioniert für Workers + TanStack Start, aber NICHT für Node.js-Deployments — die Placement-Direktive ist Cloudflare-spezifisch.

Wann jede Lösung gewinnt: Die ehrliche Entscheidungsmatrix

Die Frage ist nicht „welches ist schneller". Sie lautet „welches ist schneller für die Workload, die Sie haben". Basierend auf 91 Tagen Daten finden Sie hier die ehrliche Matrix:

WorkloadVite SPATanStack StartGewinner
Einseitiges SaaS (<500ms RTT)GutBesserTanStack Start
Multi-Region SaaS, bildlastigAkzeptabelAm besten (mit Image Resizing)TanStack Start
Single-Page-App, kein SEO-BedarfBesserÜberdimensioniertVite SPA
SEO-Landingpage, geringer TrafficAkzeptabelBesserTanStack Start
SEO-Landingpage, viraler BurstRiskantAm besten (Streaming + Cache)TanStack Start
Internes Tool, kein SEOAm bestenÜberdimensioniertVite SPA

Für die umfassendere Framework-Entscheidung und Bundle-Größen-Mathematik lesen Sie die Vite vs TanStack Start: Feldnotizen zum Upgrade-Zeitpunkt und die TanStack vs Next.js 2026 SEO-Produktionsschlacht Daten.


Offenlegung: Keine materielle Verbindung zu den besprochenen Tools. Ich zahle Listenpreise für Cloudflare Workers, Vite und TanStack Start. Die SaaS-Apps in diesem Bericht laufen auf TanStack Ship, dem Produktions-Starter, den ich pflege — lesen Sie die Preisseite für die aktuelle Build-Konfiguration. Getestet mit Vite 6.0 + TanStack Start 1.0.0 im Q1 2026. Ihre Ergebnisse können je nach Region, Bild-Pipeline und Anzahl der Third-Party-Tags variieren.