veza/apps/web/dev_audit/frontend/07_performance_analysis.md
senke f64a85414c refactor: Phase 1 — SUMI token foundation
- Rewrite index.css with complete SUMI token system (dark + light themes)
- All --sumi-* variables: backgrounds, surfaces, borders, text, pigments,
  spacing, radius, shadows, glass, scrollbar, motion, z-index, layout
- shadcn/Radix semantic mapping (--background, --foreground, etc.)
- Tailwind @theme mapping with new fonts (Inter, Space Grotesk, JetBrains Mono)
- SUMI keyframe animations (sumi-fade-in, sumi-slide-up, sumi-scale-in, etc.)
- Delete 11 redundant CSS files (design-system.css, design-tokens.css,
  button.css, card.css, input.css, badge-avatar.css, header.css,
  fix-input-focus.css, fix-login-form.css, visual-enhancements.css,
  premium-utilities.css)
- Update main.tsx: single CSS import (index.css only)
- Update ThemeProvider: data-theme attribute instead of .dark class toggle
- Update index.html FOUC script: data-theme attribute

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 01:48:01 +01:00

7.4 KiB

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