Code splitting et lazy loading avec Claude Code
Implémentez le code splitting React/Next.js avec Claude Code: exemples, étapes, pièges, vérification et CTA.
Quand une application React ou Next.js devient lente, le problème vient souvent du JavaScript initial. Le lecteur veut seulement lire une page ou cliquer sur un CTA, mais le navigateur télécharge aussi des écrans d’administration, des éditeurs, des graphiques et des widgets inutiles au premier affichage.
Le code splitting consiste à diviser ce JavaScript en fichiers plus petits. Le lazy loading consiste à charger un morceau seulement lorsqu’il devient nécessaire. L’objectif n’est pas de tout rendre différé, mais de protéger le premier écran.
Ce guide montre comment demander à Claude Code une modification contrôlable: React.lazy, Suspense, import() dynamique, next/dynamic, découpage par routes/pages, risques d’hydration et vérification. Pour compléter le sujet, consultez aussi l’analyse de bundle, le tree shaking et l’optimisation des performances.
Définitions rapides
Un bundle est le paquet JavaScript envoyé au navigateur. Un chunk est un fichier plus petit créé après découpage. Un dynamic import, comme import("./Chart"), charge un module à l’exécution. Suspense est la frontière React qui affiche une UI de repli pendant le chargement.
hydration désigne le moment où le JavaScript côté client attache événements et état au HTML déjà rendu par le serveur. Si le serveur et le client ne produisent pas le même affichage, vous obtenez une erreur d’hydration. Les lectures précoces de window, localStorage, date courante ou valeurs aléatoires sont des causes fréquentes.
| Candidat | Pourquoi le découper | Point de vigilance |
|---|---|---|
| Admin et paramètres | Rarement utiles au visiteur initial | États d’autorisation et de chargement |
| Graphiques, cartes, éditeurs | Dépendances lourdes | Réserver l’espace pour éviter le décalage |
| Modales et assistants | Nécessaires après une action | Précharger si le premier clic paraît lent |
| Recherche, vidéo, audio | Souvent plus bas dans la page | Accessibilité et messages d’erreur |
Cadrer la demande à Claude Code
Une demande vague produit souvent trop de découpage. Donnez plutôt des limites.
Objectif:
- Charger en différé l’UI lourde non nécessaire au premier écran.
- Ne pas déplacer le hero, le texte, la navigation ou le CTA derrière du lazy loading.
- Utiliser React.lazy/Suspense ou next/dynamic selon le framework.
Fichiers ciblés:
- src/features/reports/ReportsPanel.tsx
- src/features/editor/RichEditor.tsx
- app/admin/page.tsx
Vérification:
- npm run lint
- npm run build
- Comparer le JS initial et les chunks différés dans Network.
- Vérifier le mobile pour que le fallback ne couvre pas le CTA.
Cela protège les éléments qui servent à comprendre l’offre, s’inscrire ou acheter.
React.lazy et Suspense
La documentation React explique que lazy reporte le chargement du code d’un composant jusqu’à son premier rendu, tandis que Suspense affiche un fallback. Déclarez les composants lazy au niveau du module, pas à l’intérieur d’un composant.
// 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 }}>
Chargement des rapports...
</div>
);
}
export default function App() {
const [showReports, setShowReports] = useState(false);
return (
<main>
<h1>Tableau de bord</h1>
<button type="button" onClick={() => setShowReports(true)}>
Afficher les rapports
</button>
{showReports ? (
<Suspense fallback={<PanelSkeleton />}>
<ReportsPanel />
</Suspense>
) : (
<p>L’interface lourde de reporting se charge seulement à la demande.</p>
)}
</main>
);
}
// src/ReportsPanel.tsx
const rows = [
{ label: "Lecture complète", value: "68%" },
{ label: "Clics CTA", value: "4.2%" },
{ label: "Visites consultation", value: "1.1%" },
];
export default function ReportsPanel() {
return (
<section aria-label="Rapports">
<h2>Rapport de conversion</h2>
<ul>
{rows.map((row) => (
<li key={row.label}>
{row.label}: {row.value}
</li>
))}
</ul>
</section>
);
}
lazy attend un default export. Pour un named export, adaptez la valeur retournée.
// 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>Chargement du graphique...</p>}>
<BarChart />
</Suspense>
);
}
Import dynamique dans Next.js
Next.js découpe déjà le code autour des pages et routes. Utilisez next/dynamic lorsqu’un Client Component est lourd ou dépend des API du navigateur. Placez import() dans dynamic() et gardez la déclaration au niveau du module.
// 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 }}>
Chargement de l’éditeur...
</p>
),
});
export default function EditorSlot() {
return <RichEditor initialMarkdown="# Draft" />;
}
// app/admin/page.tsx
import EditorSlot from "./EditorSlot";
export default function AdminPage() {
return (
<main>
<h1>Éditeur d’article</h1>
<p>Le texte et le CTA s’affichent d’abord. Seul l’éditeur lourd est différé.</p>
<EditorSlot />
</main>
);
}
ssr: false est utile pour un éditeur dépendant du navigateur. Il est dangereux pour le texte SEO, les prix, la FAQ ou le CTA principal, car ces éléments ne seront pas présents dans le HTML serveur.
Découpage par routes et pages
Commencez par les routes avant de découper chaque composant. Dans Next.js, des fichiers séparés comme app/reports/page.tsx et app/settings/page.tsx forment déjà des frontières naturelles. Dans React Router, lazy-loadez les composants de route.
// 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">Chargement de la page...</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>
);
}
Ne placez pas toute une page marketing dans un seul grand Suspense. Le titre, le message principal et le CTA doivent rester visibles.
Cas d’usage concrets
Premier cas: un dashboard SaaS. La navigation et les métriques de base chargent tout de suite; les graphiques avancés, logs d’audit et exports CSV arrivent après vérification du rôle.
Deuxième cas: une plateforme éditoriale ou de formation. Le contenu, les titres de leçon et le CTA d’achat restent visibles. L’éditeur Markdown, le recadrage d’image et l’aperçu peuvent charger plus tard.
Troisième cas: une landing page avec carte, vidéo, calculateur ou graphique. La proposition de valeur arrive immédiatement; les widgets lourds chargent au scroll ou au clic. Pour les médias, voir lecteur vidéo et accessibilité.
Quatrième cas: une modale de devis ou de checkout. Le bouton est disponible dès le départ, puis le formulaire multi-étapes se charge à la demande.
Pièges fréquents
- Découper trop finement multiplie les requêtes et peut ralentir les interactions.
- Déclarer
lazyoudynamicdans un composant peut réinitialiser l’état. - Un fallback sans hauteur fixe provoque des décalages visuels.
- Les erreurs d’hydration viennent souvent d’un rendu serveur/client différent.
- Le contenu SEO ou monétisable ne doit pas être caché derrière
ssr: false.
Vérification
Demande de review à Claude Code:
- Confirme que lazy/dynamic sont déclarés au niveau du module.
- Vérifie default export contre named export.
- Vérifie si les frontières Suspense sont trop larges.
- Confirme que ssr:false ne cache pas le SEO ou les CTAs.
- Cherche les risques window/date/random/localStorage.
- Explique comment comparer JS initial, chunks lazy et nombre de requêtes.
npm run lint
npm run build
Ensuite, ouvrez DevTools, filtrez Network sur JS, rechargez, puis vérifiez que les chunks lourds ne sont pas chargés au départ. Cliquez sur le rapport, l’éditeur ou la modale et vérifiez que le chunk apparaît à ce moment-là.
Liens officiels et CTA
Référez-vous aux sources officielles: React lazy, React Suspense, Next.js Lazy Loading et Next.js Layouts and Pages.
Pour transformer cette méthode en routine, commencez par le cheatsheet Claude Code gratuit. Pour des prompts réutilisables d’implémentation et de review, utilisez 50 Claude Code Prompt Templates. Pour une équipe qui veut structurer CLAUDE.md, les règles de review et l’optimisation de performance, passez par la formation et consultation.
Note de terrain
Le résultat a été le plus stable quand les contenus protégés étaient définis avant le code: premier écran, navigation et CTA restent rendus côté serveur; rapports et éditeur passent en chunks différés. Une demande vague comme « rends ça lazy » produit souvent des frontières Suspense trop larges et du ssr: false inutile.
PDF gratuit: cheatsheet Claude Code
Saisissez votre email et téléchargez une page avec commandes, habitudes de review et workflow sûr.
Nous protégeons vos données et n'envoyons pas de spam.
À propos de l'auteur
Masa
Ingénieur spécialisé dans les workflows pratiques avec Claude Code.
Articles liés
Échelle de sécurité des permissions Claude Code
Passer du read-only aux éditions limitées, preuves et checks de déploiement sans perdre le contrôle.
Claude Code Small PR Proof Pack : rendre les petits changements reviewables
Un pack de preuve pour PR Claude Code : diff, vérifications, URL publique, CTA et rollback.
Gate de review avant commit avec Claude Code
Review avant commit avec Claude Code : diff, build, URL publique, liens Gumroad, CTA consultation, tests manquants et fichiers hors scope.