Tips & Tricks (Aktualisiert: 2.6.2026)

Code Splitting und Lazy Loading mit Claude Code

React- und Next.js-Code Splitting mit Claude Code sicher umsetzen: Beispiele, Fallstricke, Prüfungen und CTA-Hinweise.

Code Splitting und Lazy Loading mit Claude Code

Wenn eine React- oder Next.js-Anwendung langsam wirkt, liegt es oft nicht an einem einzelnen Button, sondern am JavaScript-Bundle. Die Startseite braucht vielleicht nur Text, Navigation und einen CTA, aber der Browser lädt zusätzlich Adminseiten, Diagramme, Editor-Code und Medienfunktionen.

Code Splitting bedeutet, dieses JavaScript in kleinere Chunks zu teilen. Lazy Loading bedeutet, einen Chunk erst zu laden, wenn er wirklich gebraucht wird. Praktisch gesagt: Nicht jeder Besucher muss das Werkzeug für jede spätere Funktion sofort herunterladen.

Dieser Leitfaden zeigt, wie du Claude Code gezielt einsetzt: mit React.lazy, Suspense, dynamischem import(), next/dynamic, Routen- und Seiten-Splitting, Hydration-Prüfung und einem klaren Review. Ergänzend passen Bundle-Analyse, Tree Shaking und Performance-Optimierung.

Begriffe kurz erklärt

Ein bundle ist das JavaScript-Paket, das an den Browser geht. Ein chunk ist eine kleinere Datei nach der Aufteilung. Ein dynamic import wie import("./Chart") lädt ein Modul zur Laufzeit. Suspense ist die React-Grenze, die während des Ladens ein Fallback anzeigt.

hydration bedeutet, dass Browser-JavaScript an bereits vom Server gerendertes HTML Ereignisse und Zustand anhängt. Wenn Server- und Client-Ausgabe unterschiedlich sind, entstehen Hydration-Fehler. Besonders riskant sind frühe Zugriffe auf window, localStorage, Uhrzeit oder Zufallswerte.

KandidatWarum geeignetAchtung
AdminbereicheFür die meisten Besucher irrelevantAuth- und Ladezustand klar darstellen
Diagramme, Karten, EditorenHäufig große BibliothekenPlatz reservieren, damit nichts springt
Modale und AssistentenErst nach Klick nötigBei langsamen Klicks vorladen
Medien- und SuchwidgetsOft unterhalb des ersten BildschirmsTastatur und Screenreader mitprüfen

Claude Code sauber beauftragen

Eine gute Aufgabe beschreibt Ziel, Grenzen und Prüfung. So vermeidest du, dass Claude Code wichtige Inhalte hinter Lazy Loading versteckt.

Ziel:
- Schwere UI lazy-loaden, wenn sie nicht für den ersten Screen nötig ist.
- Hero, Artikeltext, Navigation und CTA nicht hinter Lazy Loading verschieben.
- Je nach Framework React.lazy/Suspense oder next/dynamic verwenden.

Zieldateien:
- src/features/reports/ReportsPanel.tsx
- src/features/editor/RichEditor.tsx
- app/admin/page.tsx

Prüfung:
- npm run lint
- npm run build
- Im Network-Tab initiales JS und Lazy-Chunks vergleichen.
- Mobile Ansicht prüfen, damit das Fallback keinen CTA überdeckt.

React.lazy und Suspense

Die React-Dokumentation beschreibt lazy als Möglichkeit, Komponenten-Code erst beim ersten Rendern zu laden. Suspense zeigt währenddessen das Fallback. Wichtig: Lazy-Komponenten auf Modulebene deklarieren, nicht innerhalb einer Komponente.

// src/App.tsx
import { Suspense, lazy, useState } from "react";

const ReportsPanel = lazy(() => import("./ReportsPanel"));

function PanelSkeleton() {
  return (
    <div role="status" aria-live="polite" style={{ minHeight: 180 }}>
      Berichte werden geladen...
    </div>
  );
}

export default function App() {
  const [showReports, setShowReports] = useState(false);

  return (
    <main>
      <h1>Dashboard</h1>
      <button type="button" onClick={() => setShowReports(true)}>
        Berichte anzeigen
      </button>

      {showReports ? (
        <Suspense fallback={<PanelSkeleton />}>
          <ReportsPanel />
        </Suspense>
      ) : (
        <p>Die schwere Reporting-UI wird erst bei Bedarf geladen.</p>
      )}
    </main>
  );
}
// src/ReportsPanel.tsx
const rows = [
  { label: "Artikel gelesen", value: "68%" },
  { label: "CTA-Klicks", value: "4.2%" },
  { label: "Beratungsaufrufe", value: "1.1%" },
];

export default function ReportsPanel() {
  return (
    <section aria-label="Berichte">
      <h2>Conversion-Bericht</h2>
      <ul>
        {rows.map((row) => (
          <li key={row.label}>
            {row.label}: {row.value}
          </li>
        ))}
      </ul>
    </section>
  );
}

lazy erwartet einen Default Export. Bei Named Exports hilft ein kleiner Wrapper.

// src/lazyNamed.tsx
import { lazy, type ComponentType } from "react";

export function lazyNamed<TModule, TName extends keyof TModule>(
  loader: () => Promise<TModule>,
  name: TName
) {
  return lazy(async () => {
    const module = await loader();
    return {
      default: module[name] as ComponentType,
    };
  });
}
// src/AnalyticsSlot.tsx
import { Suspense } from "react";
import { lazyNamed } from "./lazyNamed";

const BarChart = lazyNamed(() => import("./charts"), "BarChart");

export function AnalyticsSlot() {
  return (
    <Suspense fallback={<p>Diagramm wird geladen...</p>}>
      <BarChart />
    </Suspense>
  );
}

Next.js dynamic Import

Next.js trennt Code bereits entlang von Seiten und Routen. next/dynamic ist sinnvoll, wenn eine bestimmte Client Component groß ist oder Browser-APIs braucht. Der import() gehört direkt in den dynamic()-Aufruf und die Deklaration auf Modulebene.

// app/admin/EditorSlot.tsx
"use client";

import dynamic from "next/dynamic";

const RichEditor = dynamic(() => import("./RichEditor"), {
  ssr: false,
  loading: () => (
    <p aria-live="polite" style={{ minHeight: 160 }}>
      Editor wird geladen...
    </p>
  ),
});

export default function EditorSlot() {
  return <RichEditor initialMarkdown="# Draft" />;
}
// app/admin/page.tsx
import EditorSlot from "./EditorSlot";

export default function AdminPage() {
  return (
    <main>
      <h1>Artikeleditor</h1>
      <p>Text und CTA erscheinen sofort, nur der schwere Editor wird verzögert.</p>
      <EditorSlot />
    </main>
  );
}

ssr: false ist nützlich für browserabhängige Editoren, aber schlecht für Artikeltext, Preise, FAQ oder Haupt-CTA. Solche Inhalte sollten serverseitig sichtbar bleiben.

Routen und Seiten zuerst teilen

Beginne mit Routen, bevor du jede kleine Komponente splittest. In Next.js sind getrennte Dateien wie app/reports/page.tsx und app/settings/page.tsx ein natürlicher Schnitt. In React Router kannst du Routenkomponenten lazy laden.

// src/AppRouter.tsx
import { Suspense, lazy } from "react";
import { BrowserRouter, Link, Route, Routes } from "react-router-dom";

const HomePage = lazy(() => import("./pages/HomePage"));
const ReportsPage = lazy(() => import("./pages/ReportsPage"));
const SettingsPage = lazy(() => import("./pages/SettingsPage"));

function RouteFallback() {
  return <p aria-live="polite">Seite wird geladen...</p>;
}

export default function AppRouter() {
  return (
    <BrowserRouter>
      <nav>
        <Link to="/">Home</Link>
        <Link to="/reports">Reports</Link>
        <Link to="/settings">Settings</Link>
      </nav>
      <Suspense fallback={<RouteFallback />}>
        <Routes>
          <Route path="/" element={<HomePage />} />
          <Route path="/reports" element={<ReportsPage />} />
          <Route path="/settings" element={<SettingsPage />} />
        </Routes>
      </Suspense>
    </BrowserRouter>
  );
}

Praktische Use Cases

Erstens: SaaS-Dashboards. Shell, Navigation und Kernmetriken kommen sofort; Admin-Analysen, Audit Logs, CSV-Export und Diagrammbibliotheken kommen nach Rollenprüfung.

Zweitens: Redaktions- und Kursplattformen. Artikeltext, Lektionstitel und Kauf-CTA bleiben sichtbar. Markdown-Editor, Bildzuschnitt und Vorschau dürfen verzögert laden.

Drittens: Landingpages mit Karten, Videos, Rechnern oder Diagrammen. Die Value Proposition und der nächste Schritt müssen sofort erscheinen; schwere Widgets können nach Scroll oder Klick folgen. Für Medien-UI siehe auch Video-Player und Accessibility.

Viertens: Angebots- oder Checkout-Modale. Der Button ist sofort da, der mehrstufige Dialog lädt erst bei Bedarf. Wenn der erste Klick zu langsam ist, wird beim Sichtbarwerden des Buttons vorgeladen.

Fallstricke

  1. Zu starkes Splitten erzeugt viele kleine Requests und kann Interaktionen verlangsamen.
  2. lazy oder dynamic innerhalb einer Komponente kann State zurücksetzen und Preloading verhindern.
  3. Ein Fallback ohne feste Höhe verursacht Layout Shift und verdeckt im schlimmsten Fall CTAs.
  4. Hydration-Fehler entstehen, wenn Server und Client unterschiedliche Werte rendern.
  5. SEO- und Umsatzinhalte gehören nicht leichtfertig hinter ssr: false.

Prüfung

Review-Auftrag an Claude Code:
- Prüfe lazy/dynamic-Deklarationen auf Modulebene.
- Prüfe Default Export gegen Named Export.
- Prüfe, ob Suspense-Grenzen zu groß sind.
- Prüfe, ob ssr:false SEO-Text oder CTA versteckt.
- Suche nach window/date/random/localStorage-Risiken.
- Beschreibe den Vergleich von initialem JS, Lazy-Chunks und Request-Anzahl.
npm run lint
npm run build

Danach im Browser Network auf JS filtern: Beim Reload sollten Editor- oder Admin-Chunks fehlen. Nach Klick oder Navigation sollten sie gezielt erscheinen. Prüfe zusätzlich mobile Breite.

Nutze die offiziellen Quellen: React lazy, React Suspense, Next.js Lazy Loading und Next.js Layouts and Pages.

Für einen wiederholbaren Claude-Code-Ablauf beginne mit dem kostenlosen Cheatsheet. Für wiederverwendbare Review- und Implementierungs-Prompts nutze 50 Claude Code Prompt Templates. Wenn ein Team Regeln, CLAUDE.md und Performance-Reviews gemeinsam aufsetzen will, ist Training und Beratung der passendere nächste Schritt.

Praxisergebnis

In der praktischen Prüfung funktionierte der Ansatz am besten, wenn geschützte Inhalte vorab festgelegt waren: erster Screen, Navigation und CTA blieben servergerendert; Reports und Editor wanderten in Lazy-Chunks. Eine vage Bitte wie „mach es lazy“ führte dagegen zu zu breiten Suspense-Grenzen und unnötigem ssr: false.

#Claude Code #Code Splitting #Performance #React #Next.js
Kostenlos

Kostenloses PDF: Claude-Code-Cheatsheet

E-Mail eintragen und eine Seite mit Befehlen, Review-Gewohnheiten und sicheren Workflows herunterladen.

Wir schützen Ihre Daten und senden keinen Spam.

Masa

Über den Autor

Masa

Engineer für praktische Claude-Code-Workflows und Team-Einführung.