pagespeed-test.de

Case-Study · React 18 SPA, Vite, TanStack Router, B2B-Dashboard

Case-Study: React-Bundle radikal verkleinert

B2B-Dashboard. Vorher 470 KB Initial-JS, nachher 110 KB. INP fiel von 540 ms auf 180 ms.

Metriken vor / nach

Lighthouse

64 89

LCP

2.8 s 1.8 s

INP

540 ms 180 ms

CLS

0.03 0.03

Maßnahmen

  • moment.js → date-fns (286 KB Einsparung)
  • lodash full → lodash-es named imports (52 KB)
  • React.lazy für 80 % der Routes
  • Recharts → Tremor/SVG-eigen (40 KB)
  • Vendor-Bundle aufgesplittet in 5 Chunks

B2B-Dashboard mit ~3.000 täglichen Sessions. React 18 SPA, gebaut mit Vite 4. Lighthouse-Score Mobile bei 64, INP im Field-Bereich bei 540 ms (rot). Bundle-Analyzer zeigte initial 470 KB komprimiert.

Bundle-Audit

Vite-Bundle-Visualizer zeigte folgende Top-Brocken:

  • moment.js + moment-timezone: 286 KB (60 % des Bundles!)
  • recharts: 142 KB
  • lodash (full import): 72 KB
  • react + react-dom: 130 KB
  • App-Code: 80 KB

Maßnahme 1: moment.js → date-fns (-280 KB)

Größter Einzelschritt. Die App nutzte ~12 verschiedene moment-Funktionen (format, fromNow, add, subtract, diff, isBefore, isAfter, etc.). Migration auf date-fns mit tree-shaking dauerte einen halben Tag. Vorher importiert 290 KB für 12 Funktionen, nachher 8 KB für die gleichen Funktionen.

Maßnahme 2: lodash full → lodash-es (-52 KB)

import _ from 'lodash' bundelt alle 200+ Funktionen, davon brauchte die App ~15 (debounce, throttle, groupBy, omit, pick, etc.). Switch auf import { debounce } from 'lodash-es'. Tree-Shaking reduzierte den Footprint auf 20 KB.

Maßnahme 3: React.lazy für Route-Chunks (-180 KB initial)

Vorher waren alle 14 Routes synchron importiert. Mit React.lazy + Suspense wurden 11 davon async. Initial-Route lädt nur noch ihre eigenen Komponenten + den Vendor-Core. Andere Routes lädt der Browser bei Navigation nach.

Maßnahme 4: Recharts → Tremor (-100 KB)

Recharts ist mächtig aber schwer (142 KB). Die App nutzte nur 4 Chart-Typen (Bar, Line, Donut, Number). Migration auf Tremor (~40 KB) + zwei custom-SVG-Components für sehr spezielle Fälle. Visuelle Qualität bleibt gleich.

Maßnahme 5: Vendor-Chunk-Splitting

Vite-Config angepasst: manualChunks für react, react-router, tanstack/query, charts und shared-utils. Statt einem 200 KB Vendor-Bundle: 5 kleinere Chunks die der Browser parallel lädt und einzeln cached.

Ergebnis

MetrikVorherNachher
Initial JS (gzip)470 KB110 KB
LCP2,8 s1,8 s
INP540 ms180 ms
Lighthouse Mobile6489

Aufwand: 2 Tage. moment.js-Migration war 60 % der Arbeit, restliche Maßnahmen je 1-2 Stunden.