198 lines
7.4 KiB
Markdown
198 lines
7.4 KiB
Markdown
|
|
# 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 `<img>`
|
||
|
|
- ✅ 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 `<link rel="preload">` 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 |
|