# PHASE G — PERFORMANCE --- ## G1. Bundle ### Build status - 🔴 **Le build échoue actuellement** — import manquant `educationService` dans `useEducationView.ts` - Analyse basée sur le **dernier build réussi** dans `dist_verification/` ### Taille du build (dernier build disponible) | Catégorie | Taille | Verdict | |-----------|--------|---------| | **Total dist/** | **6.8 MB** | ⚠️ Élevé (includes mockServiceWorker) | | **JS total** | ~1.4 MB | ⚠️ Significatif | | **CSS total** | ~150 KB | ✅ Raisonnable | ### Chunks JS (triés par taille) | Chunk | Taille | Contenu | |-------|--------|---------| | `vendor-*.js` | **925 KB** | Dépendances générales (axios, zustand, framer-motion, etc.) | | `index-*.js` | **113 KB** | Code applicatif principal | | `vendor-react-*.js` | **85 KB** | React + React DOM | | `vendor-utils-*.js` | **37 KB** | date-fns, zod | | `routes-*.js` | **33 KB** | Route definitions | | `vendor-tanstack-*.js` | **21 KB** | TanStack React Query | | `TrackDetailPage-*.js` | **21 KB** | Page lazy-loaded | | `vendor-icons-*.js` | **17 KB** | Lucide icons | | `SettingsPage-*.js` | **17 KB** | Page lazy-loaded | | `ChatPage-*.js` | **17 KB** | Page lazy-loaded | ### Problèmes identifiés | Problème | Impact | Fichier | |----------|--------|---------| | `vendor-*.js` à 925 KB | 🔴 Chunk vendor monolithique trop gros | `vite.config.ts:85-98` | | `mockServiceWorker.js` dans le build | ⚠️ 13 KB de MSW en production | Build output | | `swagger-ui-react` en production deps | ⚠️ Potentiellement inclus dans vendor | `package.json` | | `rollup-plugin-visualizer` en production deps | ⚠️ Devrait être en devDependencies | `package.json` | ### Tree-shaking - ✅ Imports nommés pour `lucide-react` (vendor-icons à 17 KB — excellent pour ~50 icônes) - ✅ Manual chunks configurés pour React, Router, TanStack, icons, utils - ⚠️ Le chunk `vendor` de 925 KB suggère un tree-shaking incomplet des dépendances principales - ⚠️ `emoji-picker-react` (~200 KB), `framer-motion` (~30 KB), `hls.js` (~50 KB) probablement dans vendor ### Source maps - ✅ `sourcemap: 'hidden'` en production — source maps générées mais non exposées publiquement --- ## G2. Code splitting ### React.lazy() | Fichier | Composant lazy | Usage | |---------|---------------|-------| | `components/ui/lazy-component/createLazyComponent.tsx:48` | Route components | ✅ Toutes les routes | | `features/chat/components/ChatMessage.tsx:11` | EmojiPicker | ✅ Composant lourd | | `features/chat/components/ChatInput.tsx:31` | EmojiPicker | ✅ Composant lourd | | `components/ui/ImageCropper.tsx:4` | Cropper | ✅ Composant lourd | | `components/feedback/LazyToaster.tsx:15` | Toaster | ✅ Non-critique | ### Routes lazy-loadées - ✅ **100% des routes** sont lazy-loaded via `createLazyComponent` - ✅ Chaque page a son propre chunk (TrackDetailPage-*.js, ChatPage-*.js, etc.) ### Composants lourds | Composant | Lazy-loaded ? | Taille estimée | |-----------|--------------|---------------| | EmojiPicker | ✅ Oui | ~200 KB | | ImageCropper | ✅ Oui | ~50 KB | | SwaggerUI | ❌ **Non** | ~2 MB potentiel | | Charts | ❌ **Non** | Variable | | WaveformVisualizer | ❌ **Non** | ~20 KB | **Problème** : `swagger-ui-react` n'est PAS lazy-loaded — s'il est importé dans un composant non-lazy, il pourrait gonfler le bundle principal. --- ## G3. Optimisation du rendu ### Memoization | Hook | Instances | Verdict | |------|-----------|---------| | `useMemo` | ~50+ | ✅ Bien utilisé (filtered lists, expensive computations) | | `useCallback` | ~80+ | ✅ Bien utilisé (event handlers, child callbacks) | | `React.memo` | 5 | ⚠️ Sous-utilisé (TrackCard, PlaylistCard, CourseCard, ProductCard, PostCard) | **`React.memo` manquant** : - Les composants de liste (`TrackGrid`, `PlaylistList`) bénéficieraient de `React.memo` sur les items - Les items des menus de navigation pourraient être memoizés ### useEffect | Métrique | Valeur | |----------|--------| | Total useEffect | ~200+ instances | | Fichiers avec 5+ useEffect | 2-3 (`App.tsx`, `usePlayer.ts`) | ⚠️ `App.tsx` avec 6+ useEffect est un signal de surcharge — devrait être décomposé. ### Context providers trop larges - ⚠️ `AuthContext` et `ThemeContext` wrappent toute l'application — tout changement d'état provoque un re-render de l'arbre entier - ✅ Zustand stores avec selectors ne causent pas de re-renders en cascade - ✅ React Query cache est indépendant du rendu ### Listes sans key ou avec key={index} - ⚠️ **100+ instances** de `key={index}` ou `key={i}` - La plupart sont des **skeletons et listes statiques** — acceptable - ⚠️ Certaines listes dynamiques (dashboard, chat messages) pourraient utiliser des IDs stables --- ## G4. Assets ### Images - ❌ **Aucun `loading="lazy"`** détecté sur les `` - ✅ Composant `OptimizedImage` avec blur placeholder et fallback - ⚠️ Pas de WebP/AVIF automatique (pas de pipeline d'optimisation d'images détecté) - ⚠️ Pas de `srcset` ou `sizes` pour les images responsives ### Fonts - ⚠️ Pas de `@font-face` déclarations — fonts chargées via Google Fonts (externe) - ⚠️ Pas de `font-display: swap` explicite dans le CSS (dépend du chargement Google Fonts) - ⚠️ Pas de `` pour les fonts - Fonts utilisées : Barlow, Inter, Noto Sans JP, JetBrains Mono, Orbitron, Source Serif 4 — **6 familles de polices** est excessif ### SVG - ✅ 5 fichiers SVG — faible impact - ✅ Pas de SVG inlinés massifs détectés --- ## G5. Requêtes réseau ### Waterfall - ✅ React Query avec `staleTime: 1min` évite les requêtes redondantes - ✅ Request deduplication dans le client API - ⚠️ Pas de prefetching détecté (pas de `queryClient.prefetchQuery`) - ⚠️ Routes lazy-loaded + données = double waterfall (JS chunk + API call) ### Cache HTTP - ✅ Response caching côté client dans le API client - ✅ React Query gcTime de 5 minutes - [DONNÉES INSUFFISANTES — headers Cache-Control côté serveur non analysés] ### WebSocket - ✅ Reconnection automatique avec exponential backoff - ✅ Max 5 tentatives de reconnection - ⚠️ Pas de heartbeat/ping explicite détecté dans `websocket.ts` --- ## SCORE PERFORMANCE : 6/10 ### Points gagnés | Point | Score | Justification | |-------|-------|---------------| | 100% routes lazy-loaded | +1.5 | Excellent code splitting au niveau route | | Manual chunks Vite | +0.8 | React, router, tanstack, icons séparés | | React Query cache | +0.8 | staleTime, gcTime, deduplication | | Memoization hooks | +0.7 | useMemo/useCallback bien utilisés | | Composants lourds lazy | +0.5 | EmojiPicker, ImageCropper | | Source maps hidden | +0.3 | Pas exposés en production | | Virtualization | +0.4 | TanStack Virtual pour les listes longues | ### Points perdus | Point | Score | Justification | |-------|-------|---------------| | Build cassé | -1.0 | Impossible de déployer | | Vendor chunk 925 KB | -0.8 | Chunk monolithique trop gros | | Pas de loading="lazy" images | -0.5 | Toutes les images chargées eagerly | | 6 familles de fonts | -0.5 | Impact LCP et FOIT/FOUT | | SwaggerUI non lazy | -0.3 | Potentiel 2 MB dans le bundle | | React.memo sous-utilisé | -0.3 | 5 instances seulement | | Pas de prefetching | -0.3 | Double waterfall routes + données | | Pas de font preload | -0.2 | Blocage de rendu potentiel | | key={index} fréquent | -0.1 | Minor mais présent |