MFormations
Modern Frontend Engineering

Chapitre 18

Chapitre 18 — Exercices

> 40 exercices pratiques classés par niveau pour valider et approfondir vos compétences front-end.

Chapitre 18 — 40 Exercices Pratiques

Niveau Débutant (Exercices 01–10)

HTML sémantique, CSS layout, JavaScript fondamentaux, Git


Exercice 01 — Page HTML Sémantique

Énoncé : Créez une page HTML complète structurée sémantiquement représentant un article de blog. La page doit inclure : un header avec navigation, un article principal avec titre, métadonnées (auteur, date), contenu texte, une image, une section de commentaires, et un footer.

Contraintes :

  • Aucune feuille de CSS (structure uniquement)
  • Utilisez uniquement des balises sémantiques HTML5 (<header>, <main>, <article>, <section>, <nav>, <aside>, <footer>)
  • Pas de <div> ou <span> sauf si absolument nécessaire
  • Texte d'exemple en français (lorem ipsum acceptable)
  • Valide W3C

Critères de validation :

  • Validation W3C passe sans erreur
  • Les 7 balises sémantiques principales sont utilisées
  • L'ordre de lecture au lecteur d'écran est logique
  • Une image avec alt descriptif est présente
  • Les commentaires ont un formulaire de soumission (non fonctionnel)

Durée estimée : 30 minutes


Exercice 02 — CV en HTML/CSS

Énoncé : Réalisez un CV au format HTML/CSS. Le CV doit contenir : photo, coordonnées, expériences professionnelles (3 minimum), formations, compétences avec barres de progression, et centres d'intérêt.

Contraintes :

  • Flexbox obligatoire pour la mise en page
  • Design responsive (mobile-first)
  • Police Google Fonts (Roboto ou Inter)
  • Palette de couleurs personnalisée via variables CSS
  • Impressum : marges adaptées pour l'impression (media query print)

Critères de validation :

  • Layout responsive : 1 colonne < 600px, 2 colonnes ≥ 600px
  • Les barres de compétences sont en CSS pur (pas de JS)
  • Variables CSS correctement nommées (--color-primary, --spacing-md, etc.)
  • L'impression (Ctrl+P) donne un rendu propre sans couleurs de fond

Durée estimée : 45 minutes


Exercice 03 — Grille CSS : Galerie d'Images

Énoncé : Créez une galerie d'images responsive utilisant CSS Grid. La galerie doit afficher 12 images avec des tailles variées, organisées en mosaïque type Pinterest.

Contraintes :

  • CSS Grid uniquement (pas de Flexbox pour le layout global)
  • Images de placeholder (picsum.photos ou équivalent)
  • Au moins 3 breakpoints (mobile, tablette, desktop)
  • Effet de survol avec overlay (titre, opacité)
  • Lazy loading des images avec l'attribut loading="lazy"

Critères de validation :

  • La grille utilise grid-template-areas pour la disposition
  • Le nombre de colonnes varie : 1 (mobile), 2 (tablette), 3-4 (desktop)
  • Les images de tailles différentes s'adaptent sans déformation
  • L'overlay apparaît en fondu au survol (transition CSS)
  • Pas de JavaScript

Durée estimée : 1 heure


Exercice 04 — JavaScript : To-Do List

Énoncé : Développez une application To-Do List en JavaScript vanilla. Fonctionnalités : ajout de tâche, marquer comme terminée, suppression, filtres (toutes/actives/terminées), et compteur de tâches restantes.

Contraintes :

  • Pas de frameworks ni de librairies (vanilla JS uniquement)
  • Stockage local (localStorage)
  • DOM manipulé proprement (pas de innerHTML pour les données utilisateur)
  • Accessibilité : les actions doivent être accessibles au clavier
  • Design responsive sans librairie CSS

Critères de validation :

  • Les tâches persistent après rechargement de la page
  • Les 3 filtres fonctionnent (toutes/actives/terminées)
  • Le compteur affiche le nombre de tâches actives
  • La soumission par Enter fonctionne
  • Un double-clic sur une tâche permet de l'éditer

Durée estimée : 1h30


Exercice 05 — Git : Collaboration Simulée

Énoncé : Simulez un workflow Git collaboratif. Créez un projet HTML simple, initialisez un dépôt Git, créez des branches, effectuez des commits, mergez avec et sans conflit, et rebasez.

Contraintes :

  • Travail en local uniquement (pas de remote)
  • Utilisez un dossier git-exercice/ en dehors du projet principal
  • Script bash des commandes à fournir en solution
  • Commit message conventionnel (Conventional Commits)

Étapes obligatoires :

  1. git init + premier commit sur main (index.html vide)
  2. Création de branche feature/header (3 commits)
  3. Création de branche feature/footer (2 commits)
  4. Merge de feature/footer sur main
  5. Création d'un conflit intentionnel sur index.html
  6. Résolution du conflit
  7. Rebase de feature/header sur main
  8. git log --graph pour visualiser l'historique

Critères de validation :

  • L'historique final montre les 3 branches avec merge et rebase
  • Le conflit est résolu avec les deux modifications conservées
  • Les messages de commit suivent le format type(scope): description
  • Le script est reproductible (effacer et ré-exécuter)

Durée estimée : 1 heure


Exercice 06 — Formulaire avec Validation

Énoncé : Créez un formulaire d'inscription complet avec validation en JavaScript. Champs : nom, email, mot de passe, confirmation, date de naissance, pays (select), et conditions d'utilisation (checkbox).

Contraintes :

  • Validation en temps réel (au fur et à mesure de la saisie)
  • Messages d'erreur spécifiques (pas de message générique)
  • Validation email par regex (pas de pattern HTML5 uniquement)
  • Force du mot de passe indiquée visuellement
  • Soumission AJAX simulée (Promise avec setTimeout)
  • Accessibilité ARIA : aria-invalid, aria-describedby, role="alert"

Critères de validation :

  • Les erreurs s'affichent/effacent en temps réel pendant la frappe
  • Le bouton de soumission est désactivé tant que le formulaire est invalide
  • Les regex sont correctes : email valide, mot de passe (8+ car, 1 maj, 1 chiffre, 1 spécial)
  • Le feedback de force du mot de passe a 3 niveaux (faible, moyen, fort)
  • La soumission montre un loader puis une confirmation

Durée estimée : 2 heures


Exercice 07 — Landing Page avec Animations CSS

Énoncé : Créez une landing page pour un produit fictif ("Nova — Assistant IA"). La page doit contenir : hero section, features (3 cartes), témoignages (carrousel), pricing (3 colonnes), et footer.

Contraintes :

  • Animations CSS au scroll (intersection observer non autorisé)
  • Utilisation de @keyframes et transition
  • Transformations 3D pour les cartes (perspective)
  • Variables CSS pour le thème
  • Performance : will-change, transform/opacity uniquement

Critères de validation :

  • Les animations se déclenchent à l'apparition dans le viewport (via classe .visible)
  • Les cartes de features ont un effet de survol 3D
  • Le carrousel de témoignages défile automatiquement avec @keyframes
  • Le pricing a 3 colonnes avec mise en avant de l'offre "Pro"
  • Aucun JavaScript pour les animations (JS uniquement pour l'intersection observer)

Durée estimée : 2 heures


Exercice 08 — API Fetch : Dashboard Météo

Énoncé : Créez une application météo qui affiche la météo actuelle et les prévisions à 5 jours pour une ville saisie par l'utilisateur.

Contraintes :

  • API gratuite : Open-Meteo (pas de clé API nécessaire) ou WeatherAPI
  • Fonctions asynchrones avec async/await
  • Gestion des erreurs : ville inexistante, réseau, timeout
  • Icônes météo (SVG inline ou emoji)
  • Graphique des températures en CSS (barres verticales)

Critères de validation :

  • La recherche fonctionne par nom de ville
  • Les données actuelles (température, humidité, vent, description) sont affichées
  • Les prévisions 5 jours sont visibles avec min/max
  • Un indicateur de chargement est présent
  • Les erreurs sont affichées proprement (pas de console.log)

Durée estimée : 2 heures


Exercice 09 — Modules ES6 : Bibliothèque de Calcul

Énoncé : Créez une bibliothèque de fonctions mathématiques organisée en modules ES6. Exportez des fonctions, importez-les dans un fichier principal, et démontrez leur utilisation dans une interface simple.

Contraintes :

  • Modules ES6 avec export / import
  • Minimum 4 modules : arithmetic.js, statistics.js, geometry.js, formatters.js
  • Utilisation de import.meta.url pour les chemins dynamiques
  • Arbres d'import avec dépendances entre modules
  • Pas de bundler (navigateur avec type="module")

Critères de validation :

  • Chaque module exporte au moins 3 fonctions
  • Le module statistics.js importe depuis arithmetic.js
  • Le fichier main.js importe les 4 modules
  • Une interface HTML simple (input/output) teste chaque fonction
  • Les imports circulaires sont évités

Durée estimée : 1h30


Exercice 10 — Accessibilité : Audit et Correction

Énoncé : Prenez la page HTML de l'exercice 01 et corrigez-la pour atteindre le niveau AA des WCAG 2.2. Auditez avec axe DevTools, Lighthouse, et manuellement (clavier, lecteur d'écran).

Contraintes :

  • Rapport Lighthouse Accessibilité ≥ 95
  • axe DevTools : 0 violations critiques/sérieuses
  • Navigation clavier complète (Tab, Enter, Escape)
  • Contraste des couleurs ≥ 4.5:1 (texte normal)
  • Structure de titres hiérarchique (h1 → h2 → h3)
  • Landmarks ARIA corrects

Critères de validation :

  • Rapport d'audit initial et final fournis
  • Tous les éléments sont accessibles au clavier
  • Les images décoratives ont aria-hidden="true"
  • Les formulaires ont des <label> explicites
  • Le lang attribute est correct
  • Les sauts de navigation (skip links) sont présents

Durée estimée : 1h30


Niveau Intermédiaire (Exercices 11–20)

React hooks, TypeScript generics, API calls, testing


Exercice 11 — Compteur avec useReducer

Énoncé : Implémentez un compteur React utilisant useReducer avec des actions typées : increment, decrement, reset, setValue, incrementByAmount, et undo.

Contraintes :

  • TypeScript strict
  • Actions typées avec discriminated unions
  • Historique des 10 dernières actions (undo)
  • Deux boutons + et - , un champ input pour setValue
  • Touche Escape pour reset

Critères de validation :

  • Le reducer est une fonction pure testée unitairement
  • L'historique undo fonctionne (y compris undo après undo)
  • setValue accepte les nombres négatifs (mais pas NaN)
  • Le type Action est un type (pas une interface)
  • action.type est correctement discriminé dans le switch

Durée estimée : 1h30


Exercice 12 — TypeScript Generics : Repository Pattern

Énoncé : Créez une classe générique Repository<T> qui implémente les opérations CRUD avec stockage en mémoire. Étendez-la avec UserRepository et ProductRepository.

Contraintes :

  • Contrainte de type : T extends { id: string }
  • Méthodes : findAll, findById, create, update, delete
  • Validation optionnelle via generic constraint
  • Utilisation de Partial<T>, Pick<T>, Omit<T> dans les signatures
  • Tests unitaires avec Vitest

Critères de validation :

  • Repository<User> fonctionne avec User = { id: string, name: string, email: string }
  • Repository<Product> fonctionne avec Product = { id: string, title: string, price: number }
  • update accepte Partial<T> (mise à jour partielle)
  • create retourne l'entité créée avec un ID auto-généré
  • Les types sont inférés sans annotations redondantes

Durée estimée : 2 heures


Exercice 13 — Custom Hook : useLocalStorage

Énoncé : Créez un hook React useLocalStorage<T> qui synchronise un état avec localStorage, avec gestion des erreurs de sérialisation et de quota dépassé.

Contraintes :

  • TypeScript avec générique T
  • Gestion des erreurs de JSON.parse (fallback vers defaultValue)
  • Gestion de quota Exceeded (try/catch dans le setter)
  • Versioning des données (migration si le format change)
  • Synchronisation entre onglets (storage event)
  • Valeur par défaut si la clé n'existe pas

Critères de validation :

  • Le hook persiste les données au rechargement
  • Si localStorage contient du JSON invalide, le fallback s'applique
  • Si le quota est dépassé, une erreur est loggée sans crash
  • Si un autre onglet modifie la valeur, le hook se met à jour
  • Le hook expose remove et clear en plus de get/set

Durée estimée : 2 heures


Exercice 14 — Appel API avec React Query

Énoncé : Créez une application de liste de posts avec React Query (TanStack Query). Fonctionnalités : liste paginée, détail d'un post, création, édition, et suppression avec mutations.

Contraintes :

  • API : JSONPlaceholder (ou équivalent)
  • Pagination avec useInfiniteQuery ou keepPreviousData
  • Mutations avec invalidation de cache optimiste
  • Loading et error states pour chaque opération
  • Retry automatique configurable (3 tentatives)

Critères de validation :

  • La liste paginée charge 10 posts par page avec navigation
  • Le cache est invalidé après création/suppression
  • L'optimistic update rollback si la mutation échoue
  • Les states loading/error/success sont correctement affichés
  • Les données sont pré-fetchées au survol du lien de détail

Durée estimée : 2h30


Exercice 15 — Tests Unitaires avec Vitest

Énoncé : Écrivez des tests unitaires complets pour un hook useCounter et pour une fonction utilitaire formatCurrency.

Contraintes :

  • Vitest comme test runner
  • Couverture de code ≥ 90%
  • Tests de cas nominaux, limites, et erreurs
  • Mock de Intl.NumberFormat pour les tests de formatCurrency
  • Tests de rendu React (Testing Library) pour le hook

Critères de validation :

  • useCounter : test initial value, increment, decrement, reset, max/min limits
  • formatCurrency : test différents formats (EUR, USD, JPY), valeurs négatives, grands nombres
  • Les mocks sont restaurés après chaque test (afterEach)
  • Les tests sont nommés clairement (describe/it)
  • Coverage ≥ 90% confirmé par Vitest

Durée estimée : 2 heures


Exercice 16 — Formulaire avec React Hook Form

Énoncé : Créez un formulaire multi-step (3 étapes) avec React Hook Form et Zod pour la validation. Étapes : Informations personnelles → Adresse → Récapitulatif et soumission.

Contraintes :

  • React Hook Form avec TypeScript
  • Schéma de validation Zod
  • Champs : nom, email, téléphone, rue, ville, code postal, pays
  • Navigation entre étapes avec validation avant de passer à l'étape suivante
  • Résumé modifiable avant soumission finale

Critères de validation :

  • La validation Zod bloque le passage à l'étape suivante
  • Les données persistent entre les étapes (même en revenant en arrière)
  • Le résumé final affiche toutes les données
  • Au moins 3 rules customs Zod (email valide, téléphone français, code postal)
  • Le formulaire est accessible (labels, erreurs aria)

Durée estimée : 2h30


Exercice 17 — Composant Carrousel Accessible

Énoncé : Créez un composant Carrousel React réutilisable avec navigation infinie et contrôle clavier complet.

Contraintes :

  • TypeScript + React
  • Props : items: T[], renderItem: (item: T) => ReactNode, autoPlay?: boolean, interval?: number
  • Navigation : flèches, dots, swipe tactile
  • Accessibilité : role="region", aria-roledescription="carousel", aria-label
  • Pause au survol et au focus
  • Boucle infinie (pas de fin)

Critères de validation :

  • Les props génériques sont correctement typées
  • Le focus est piégé dans le carrousel actif (Tab ne sort pas)
  • Les contrôles clavier : Flèche Gauche/Droite, Home/End
  • Le défilement automatique se met en pause au survol
  • Le défilement est fluide (CSS scroll-behavior ou animation)

Durée estimée : 2h30


Exercice 18 — Contexte d'Authentification

Énoncé : Créez un système d'authentification React complet avec Context API. Fonctionnalités : login, logout, inscription, refresh token, et protected routes.

Contraintes :

  • AuthProvider avec Context
  • TypeScript : User, AuthState, AuthContext
  • useAuth hook custom avec type guard
  • ProtectedRoute composant avec redirect
  • Token stocké en mémoire + refresh token en httpOnly cookie (simulé)
  • Role-based access (admin, user, guest)

Critères de validation :

  • useAuth lance une erreur si utilisé hors du Provider
  • ProtectedRoute redirige vers /login si non authentifié
  • Le refresh token est appelé automatiquement à l'expiration
  • Les rôles sont vérifiés : RequireRole="admin" bloque les utilisateurs
  • Le contexte n'expose pas les méthodes sensibles (ex: setToken)

Durée estimée : 2 heures


Exercice 19 — Pagination avec Recherche

Énoncé : Créez un hook usePaginatedQuery qui encapsule la logique de pagination, filtrage, et recherche pour une liste d'éléments.

Contraintes :

  • API : SWAPI (Star Wars API) ou équivalent
  • Paramètres : page, search, sortBy, sortOrder
  • Debounce de la recherche (300ms)
  • Query string synchronisée avec l'URL (useSearchParams)
  • Pré-chargement de la page suivante

Critères de validation :

  • Les paramètres sont persistés dans l'URL
  • La recherche est debouncée (pas d'appel API à chaque frappe)
  • Les données de la page suivante sont pré-chargées en arrière-plan
  • Le changement de tri réinitialise la pagination
  • L'historique du navigateur (back/forward) est supporté

Durée estimée : 2h30


Exercice 20 — Tests d'Intégration avec MSW

Énoncé : Écrivez des tests d'intégration pour une application React qui affiche une liste de tâches, avec MSW (Mock Service Worker) pour intercepter les appels API.

Contraintes :

  • MSW (v2) avec handlers typés
  • Vitest + Testing Library
  • Tests : chargement, succès, erreur, empty state
  • Scénario : ajout et suppression de tâche
  • Pas de mock manuel des fetch/axios

Critères de validation :

  • Les handlers MSW sont dans un fichier mocks/handlers.ts
  • Le test vérifie l'affichage du loader, puis des données
  • L'ajout de tâche mocké retourne la tâche avec un ID généré
  • La suppression met à jour la liste sans re-fetch
  • Les erreurs réseau retournent un message d'erreur approprié

Durée estimée : 2h30


Niveau Avancé (Exercices 21–30)

Performance, architecture, custom hooks, SSR


Exercice 21 — Virtual Scroll

Énoncé : Implémentez un composant VirtualList<T> qui n'affiche que les éléments visibles dans le viewport, avec défilement fluide de 10 000 éléments.

Contraintes :

  • Hauteur fixe des items configurable via itemHeight prop
  • Taille totale calculée pour la barre de défilement
  • Buffer de 3 items au-dessus et en-dessous du viewport
  • Pas de librairie externe de virtualisation
  • Support du clavier (Flèche Haut/Bas)

Critères de validation :

  • 10 000 éléments rendus → seulement ~15 nœuds DOM
  • Le défilement est fluide (60fps)
  • La position du scroll est maintenue après remplacement des données
  • Les éléments dynamiques (hauteur variable) sont gérés via mesure après rendu
  • Les éléments sont recyclés (pas de création/suppression, juste mise à jour)

Durée estimée : 3 heures


Exercice 22 — Web Worker : Traitement d'Image

Énoncé : Créez une application de traitement d'images utilisant un Web Worker pour appliquer des filtres (noir et blanc, sépia, flou gaussien) sans bloquer le thread principal.

Contraintes :

  • Canvas API pour la manipulation des pixels
  • Web Worker dédié pour le traitement
  • Transfert d'ImageData avec transferable objects
  • Barre de progression du traitement
  • Comparaison de performance (avec/sans Worker)

Critères de validation :

  • L'interface reste réactive pendant le traitement (boutons cliquables)
  • Les filtres sont appliqués correctement (matrices de convolution)
  • La progression est affichée en temps réel
  • Le transfert utilise postMessage avec transferList
  • Le benchmark montre 0ms de blocage UI avec Worker vs >500ms sans

Durée estimée : 3 heures


Exercice 23 — Custom Hook : useWebSocket

Énoncé : Créez un hook useWebSocket avec reconnexion automatique, souscription par événement, et file d'attente de messages pendant la déconnexion.

Contraintes :

  • TypeScript avec types génériques pour les messages
  • useRef pour la connexion (pas de re-rendu)
  • Exponential backoff : 1s, 2s, 4s, 8s... max 30s
  • File d'attente FIFO (max 50 messages)
  • Souscription : socket.on('event', callback) / socket.off('event', callback)
  • Ping/pong keepalive toutes les 30s

Critères de validation :

  • La reconnexion s'arrête après 5 échecs consécutifs
  • Les messages envoyés pendant la déconnexion sont mis en file d'attente
  • Les callbacks sont nettoyés au unmount
  • Le ping/pong évite la déconnexion du proxy/load balancer
  • Les souscriptions multiples au même événement sont supportées

Durée estimée : 3 heures


Exercice 24 — Architecture : Micro-frontends Module Federation

Énoncé : Configurez une architecture micro-frontends avec Webpack Module Federation : trois applications indépendantes (Header, Dashboard, Settings) intégrées dans un shell.

Contraintes :

  • Module Federation Plugin (Webpack 5)
  • Shell (host) : routing, auth, layout
  • Header (remote) : navigation, profil utilisateur
  • Dashboard (remote) : widgets métier
  • Settings (remote) : formulaire de configuration
  • Partage de bibliothèques (React, MUI/Chakra)

Critères de validation :

  • Chaque micro-frontend est déployable indépendamment
  • Le shell hydrate les remotes sans duplication de React
  • La communication inter-apps utilise un event bus personnalisé
  • Le partage de styles est cohérent (design tokens)
  • Les routes sont lazy-loadées

Durée estimée : 4 heures


Exercice 25 — Server-Side Rendering avec Next.js

Énoncé : Créez une application Next.js (App Router) avec SSR, ISR, et SSG. Pages : blog (SSG + ISR), profil utilisateur (SSR), dashboard protégé (SSR + auth), et page statique.

Contraintes :

  • Next.js 14+ App Router
  • Blog : generateStaticParams + revalidate (ISR)
  • Profil : dynamic = 'force-dynamic' + cookies()
  • Dashboard : middleware d'authentification
  • Loading states avec loading.tsx
  • Error boundaries avec error.tsx

Critères de validation :

  • La page blog est buildée statiquement puis régénérée toutes les 60s
  • Le profil utilisateur charge les données à chaque requête
  • Le middleware redirige vers /login si pas de session
  • Le loading state est visible avant l'hydratation
  • Les erreurs API sont catchées par l'error boundary

Durée estimée : 3 heures


Exercice 26 — React Query + WebSocket : Dashboard Temps Réel

Énoncé : Créez un dashboard temps réel qui combine React Query (initial data fetch) et WebSocket (mises à jour push) pour des métriques en direct.

Contraintes :

  • React Query pour le chargement initial et le cache
  • WebSocket pour les mises à jour incrémentales
  • Graphiques en temps réel (Chart.js, D3, ou Recharts)
  • Cache React Query mis à jour à la réception WebSocket
  • Reconnexion WebSocket avec gestion du cache stale

Critères de validation :

  • Les données initiales viennent de React Query (avec suspense)
  • Les mises à jour WebSocket patch les données sans re-fetch
  • Le graphique s'anime lors des nouvelles données
  • Pendant la reconnexion, React Query sert les données en cache
  • Le status de connexion WebSocket est affiché (connecté/déconnecté)

Durée estimée : 3h30


Exercice 27 — Optimisation : Bundle Splitting et Lazy Loading

Énoncé : Optimisez une application React avec React.lazy, Suspense, et analyse du bundle pour réduire la taille initiale de 70%.

Contraintes :

  • React.lazy + Suspense pour le code-splitting par route
  • webpack-bundle-analyzer ou vite-plugin-visualizer
  • Préchargement stratégique : prefetch au survol, preload pour les routes critiques
  • Page cible : bundle initial < 100KB (gzippé)
  • Composants lourds (éditeur de texte, graphiques) chargés à la demande

Critères de validation :

  • Analyse avant/après montrant la réduction
  • Bundle initial < 100KB gzippé
  • Les chunks sont nommés explicitement (/* webpackChunkName: "editor" */)
  • Le préchargement au survol est visible dans le Network tab
  • Aucun flash/loading state bizarre pendant le chargement asynchrone

Durée estimée : 2h30


Exercice 28 — Tests de Performance avec Lighthouse CI

Énoncé : Configurez Lighthouse CI sur un projet React existant pour auditer automatiquement les performances, l'accessibilité, et les bonnes pratiques à chaque PR.

Contraintes :

  • Lighthouse CI configuré dans GitHub Actions
  • Assertions : Performance ≥ 90, Accessibility ≥ 95, SEO ≥ 95
  • Budget de performance : LCP < 2.5s, TBT < 200ms, CLS < 0.1
  • Rapport détaillé avec captures d'écran des audits échoués
  • Comparaison avec la branche de base (main)

Critères de validation :

  • Le job CI lance Lighthouse sur 3 pages (accueil, article, contact)
  • Les assertions échouent si les scores sont en dessous des seuils
  • Le rapport est uploadé en artefact
  • Les métriques Web Vitals sont collectées
  • Le budget de performance bloque le merge si dépassé

Durée estimée : 2 heures


Exercice 29 — Architecture : Clean Architecture en Front-end

Énoncé : Structurez une application React selon les principes de Clean Architecture : séparation en couches (domain, application, infrastructure, presentation) avec injection de dépendances.

Contraintes :

  • Pas de dépendance directe entre la présentation et l'infrastructure
  • Domain layer : entités, value objects, repository interfaces
  • Application layer : use cases, DTOs
  • Infrastructure layer : implémentations concrètes (API, localStorage, IndexedDB)
  • Presentation layer : composants React, hooks
  • Injection de dépendances via un container (IoC) ou props

Critères de validation :

  • Changer d'API (REST → GraphQL) ne change que l'infrastructure layer
  • Les use cases sont testables sans DOM
  • Les entités sont des classes TS pures (pas de dépendances framework)
  • Le data flow est unidirectionnel : UI → UseCase → Repository → API
  • Les DTOs sont transformés en entités dans le application layer

Durée estimée : 4 heures


Exercice 30 — CI/CD Pipeline Complet

Énoncé : Créez un pipeline CI/CD complet avec GitHub Actions : lint, typecheck, tests, build, déploiement preview (PR) et production (main).

Contraintes :

  • GitHub Actions workflow YAML
  • Cache des dépendances (npm/yarn/pnpm)
  • Matrix de tests (Node 18, 20, 22)
  • Jobs parallélisés (lint + test en parallèle, build après)
  • Déploiement preview sur Vercel/Netlify
  • Notification Slack/Discord en cas d'échec

Critères de validation :

  • Le pipeline s'exécute en moins de 5 minutes
  • Les jobs sont parallélisés efficacement
  • Le cache réduit le temps d'install à < 10s
  • La PR a un commentaire avec le lien de preview
  • Le déploiement production nécessite un tag de release (v*)

Durée estimée : 3 heures


Niveau Expert (Exercices 31–40)

Micro-frontends, WebAssembly, monorepo, design system


Exercice 31 — Micro-frontends : Event Bus et Communication

Énoncé : Implémentez un event bus typé pour la communication entre micro-frontends, avec support de l'isolation et de la sécurité.

Contraintes :

  • TypeScript : EventBus<T> avec types d'événements stricts
  • Pattern : publish/subscribe avec filtrage par namespace
  • Isolation : chaque micro-frontend a son namespace
  • Bridge entre window.postMessage et l'event bus pour cross-origin
  • Sécurité : validation des origin, throttling des événements
  • DevTools : logging des événements échangés

Critères de validation :

  • events.on('dashboard:user-updated', handler) fonctionne
  • Les événements cross-origin passent par postMessage avec validation d'origin
  • Un micro-frontend malveillant ne peut pas écouter les événements d'un autre namespace
  • Le throttling limite à 60 événements par seconde
  • Les DevTools affichent un log structuré de tous les événements

Durée estimée : 3h30


Exercice 32 — WebAssembly : Traitement d'Image avec Rust/WASM

Énoncé : Créez un module WASM en Rust (via wasm-pack) qui applique un filtre de convolution sur une image, et intégrez-le dans une application React.

Contraintes :

  • Rust + wasm-pack pour la compilation WASM
  • wasm-bindgen pour l'interopérabilité JS↔Rust
  • Fonction Rust : apply_convolution(input: &[u8], width: u32, height: u32, kernel: &[f32]) -> Vec<u8>
  • Benchmark comparatif JS vs WASM
  • Gestion des erreurs Rust (panic → JS)

Critères de validation :

  • Le filtre WASM est 3-5x plus rapide que l'équivalent JS
  • L'image traitée est correcte (mêmes pixels que la version JS)
  • La mémoire WASM est libérée après traitement
  • Les panics Rust sont catchés en JS (try/catch)
  • Le build wasm-pack génère les types TypeScript

Durée estimée : 4 heures


Exercice 33 — Monorepo avec Nx

Énoncé : Configurez un monorepo Nx avec partage de code entre plusieurs applications (web, mobile, admin) et librairies partagées.

Contraintes :

  • Nx workspace (pnpm/yarn)
  • 3 apps : web (React), mobile (React Native), admin (React)
  • 5 libs : ui (design system), shared (types/utils), api (API client), auth, i18n
  • Task orchestration : dépendances entre libs
  • Cache distant (Nx Cloud ou équivalent)
  • Affected commands dans la CI

Critères de validation :

  • nx graph montre les dépendances correctes
  • nx test web teste web + ses dépendances
  • La CI ne build/lint/test que les projets affectés
  • Le cache distant est fonctionnel (second build < 1s)
  • Les libs sont versionnées avec semantic-release

Durée estimée : 4 heures


Exercice 34 — Design System avec Storybook

Énoncé : Créez un design system complet avec Storybook, incluant 10 composants, des tokens de design, et une documentation exhaustive.

Contraintes :

  • Storybook 7+ avec React + TypeScript
  • 10 composants : Button, Input, Select, Modal, Table, Badge, Tooltip, Card, Avatar, Spinner
  • Design tokens : couleurs, typographie, spacing, breakpoints, shadows
  • Chaque composant a : stories (5+ variants), docs, tests d'interaction
  • Accessibilité : axe-core addon, WCAG AA

Critères de validation :

  • Les tokens sont des variables CSS + objets TS
  • Les stories couvrent : default, disabled, loading, error, custom
  • Les tests d'interaction (play function) vérifient le comportement
  • Le dark mode est supporté (via class ou data-theme)
  • Le build Storybook est déployable statiquement

Durée estimée : 5 heures


Exercice 35 — Module Fédéré : Shared State et Routing

Énoncé : Étendez l'exercice 24 avec un state partagé entre micro-frontends et un routing distribué.

Contraintes :

  • Module Federation avancé
  • Shared store : Zustand ou Redux avec slice isolation
  • Routing distribué : chaque remote déclare ses routes dans le shell
  • Lazy loading des remotes avec loading state
  • Error boundary par remote (un remote qui crash n'affecte pas les autres)
  • Versioning des remotes (compatible semver)

Critères de validation :

  • Le store partagé est typé et isolé par namespace
  • Les routes sont enregistrées dynamiquement par chaque remote
  • Si le remote Dashboard crash, le Header continue de fonctionner
  • La navigation entre les routes des différents remotes est fluide
  • Le versioning permet de déployer différentes versions des remotes

Durée estimée : 5 heures


Exercice 36 — WebAssembly : Port d'une Librairie C

Énoncé : Portez une petite librairie C existante (ex: une librairie de compression simple) vers WebAssembly avec Emscripten, et créez une interface React.

Contraintes :

  • Emscripten (emcc) pour la compilation C → WASM
  • Wrapper JavaScript pour l'API C
  • Module WASM chargé asynchrone avec progress
  • Gestion de la mémoire manuelle (malloc/free)
  • Comparaison de taille : .wasm < 50KB

Critères de validation :

  • La fonction C est appelable depuis JS avec des paramètres typés
  • La mémoire allouée en C est libérée correctement
  • Le chargement asynchrone montre un indicateur de progression
  • Le binaire WASM final fait moins de 50KB
  • La fonction s'exécute sans fuite mémoire vérifiable

Durée estimée : 5 heures


Exercice 37 — Architecture : Event Sourcing en Front-end

Énoncé : Implémentez un système d'event sourcing côté client : chaque action utilisateur est un événement immutable, stocké dans IndexedDB, avec rejeu possible.

Contraintes :

  • Event sourcing pattern : event store, projector, read model
  • IndexedDB pour le stockage des événements avec Dexie.js
  • Rejeu : possibilité de rejouer tous les événements pour reconstruire l'état
  • Time travel : navigation dans l'historique des événements
  • Snapshotting : création périodique de snapshots pour performance
  • Undo/Redo basé sur les événements

Critères de validation :

  • Chaque événement a : id, type, payload, timestamp, version
  • Le projector met à jour le read model à partir des événements
  • Le rejeu de 1000 événements prend < 100ms
  • Le time travel permet de visualiser l'état à n'importe quel moment
  • Les snapshots sont créés tous les 50 événements

Durée estimée : 5 heures


Exercice 38 — Performance : Web Vitals et Core Web Vitals

Énoncé : Auditez et optimisez une application React pour atteindre des scores Core Web Vitals parfaits (LCP < 1.5s, FID < 50ms, CLS < 0.05).

Contraintes :

  • Optimisation LCP : preload des images critiques, optimisation du TTFB
  • Optimisation FID/INP : code splitting, idle callbacks, lazy handlers
  • Optimisation CLS : dimensions explicites, font-display: swap, skeleton screens
  • Monitoring : web-vitals library + analytics (GA4/Plausible)
  • Rapport Lighthouse ≥ 98 sur mobile

Critères de validation :

  • LCP < 1.5s (simulated throttling)
  • TBT < 100ms (simulated throttling)
  • CLS < 0.05 (simulated throttling)
  • Le rapport Lighthouse est ≥ 98 sur mobile
  • Les métriques sont envoyées à un endpoint d'analytics

Durée estimée : 4 heures


Exercice 39 — API Gateway : BFF Pattern

Énoncé : Créez un Backend For Frontend (BFF) qui agrège plusieurs APIs backend (REST, GraphQL) et sert une API adaptée au front-end.

Contraintes :

  • Node.js + Express ou Hono.js
  • Agrégation : appels parallèles avec Promise.all
  • Transformation : mapping des données au format attendu par le front
  • Cache : in-memory cache avec TTL configurable
  • Rate limiting : throttle par IP utilisateur
  • Sécurité : validation des entrées, CORS, CSP headers

Critères de validation :

  • Le BFF agrège 2 APIs backend en une seule réponse
  • Le cache réduit les appels redondants (hit ratio > 50%)
  • Le rate limiting bloque après 100 requêtes/minute
  • Les headers de sécurité sont présents (CSP, X-Frame-Options)
  • Le BFF est testé avec Supertest ou équivalent

Durée estimée : 4 heures


Exercice 40 — Full Stack : Application Complete

Énoncé : Créez une application full-stack complète (front-end React + BFF Node.js) avec authentification, CRUD, tests, CI/CD, et déploiement.

Contraintes :

  • Monorepo (pnpm workspaces ou Nx)
  • Front : React + TypeScript + Vite + TanStack Query
  • Back : Hono.js + Prisma + SQLite (ou PostgreSQL)
  • Auth : JWT avec refresh token
  • Tests : Vitest (unit) + Playwright (E2E)
  • CI/CD : GitHub Actions + Docker
  • Documentation : README + ADR

Critères de validation :

  • L'application est dockerisée et s'exécute avec docker compose up
  • Les tests unitaires couvrent ≥ 80% du code
  • Les tests E2E Playwright couvrent le parcours utilisateur complet
  • Le pipeline CI s'exécute en < 10 minutes
  • La documentation inclut ADR et diagramme d'architecture

Durée estimée : 8 heures


Récapitulatif

NiveauExercicesDurée totaleCompétences clés
Débutant01–10~10hHTML sémantique, CSS (Flexbox/Grid), JS DOM, Git
Intermédiaire11–20~15hReact hooks, TypeScript, API, testing
Avancé21–30~20hPerformance, architecture, SSR, optimisation
Expert31–40~25hMicro-frontends, WASM, monorepo, design system
Total40~70hProgramme complet