Skip to content

Plan d'enseignement - Cours 141

📌 Accéder au Padlet du cours

Vue d'ensemble des 15 séances

SéanceDateThèmeContenu principal
121.01IntroductionEnvironnement, Vue DevTools, Structure projet
228.01Création projet + BasesVuetify, Vue DevTools, ref(), ESLint
304.02Bases Vue.js + ExercicesDemo Vue.js, Exercices Classroom, Début Infomaniak
411.02Déploiement Infomaniak/VercelProjet individuel, GitHub Actions, FTP, Vercel
525.02Cycle de vie & WatchersTuto 8-10, Exercices 5-7, Présentation lifecycle
604.03Composants Vue.jsProps, Emits, Slots, Tuto 11-14, Exercices 8-9
711.03Vuetify + APIDémo Rick & Morty Explorer, lancement projet perso
825.03Setup Pokédex + Composants + Routesfetch API, grille, PokemonCard, pages, navigation
901.04Pinia (state management)Créer le store, migrer fetch, storeToRefs
1022.04Axios, .env et robustesse APIfetch → Axios, .env, loading/error
1129.04Recherche, filtre et tricomputed chaînés, filtre type, tri
1206.05Favoris et persistancetoggleFavorite, localStorage, page favoris
1313.05Formulaires, auth et suppressionv-form, POST, authStore, guards, DELETE
1420.05UX, responsive et finalisationThème, responsive, README, déploiement
1527.05Rendu projet + Examen oralRendu projet, oral 20 min

Semaines sans cours

  • 18 février (vacances)
  • 18 mars (vacances)
  • 8 avril (vacances de Pâques)
  • 15 avril (vacances de Pâques)

Séance 1 - 21 janvier 2026 ✓

Thème : Introduction à Vue.js et Vuetify

Objectifs :

  • Mettre en place l'environnement de développement
  • Comprendre Vue.js et Vuetify
  • Installer Vue DevTools
  • Créer sa première application Vue

Contenu couvert :

  • Reconnexion WebStorm/GitHub
  • Création projet avec npm create vuetify
  • Explication npm et npmjs.com (packages)
  • Choix TypeScript vs JavaScript (JS pour débutants)
  • Lancement serveur avec npm run dev
  • Installation et utilisation Vue DevTools (Firefox/Brave)
  • Inspection des composants avec DevTools
  • Structure projet : public/ vs src/
  • Flux de démarrage : index.html → main.js → App.vue
  • Hot Reload (rechargement automatique)
  • Modification du template App.vue

Ressources :

Devoirs : Tutoriel Vue.js officiel (étapes 1-7)

Séance 2 - 28 janvier 2026 ✓

Thème : Création projet Vuetify et bases Vue.js

Objectifs :

  • Créer un nouveau projet Vuetify
  • Comprendre la structure d'un projet Vue.js
  • Découvrir les variables réactives et les directives

Devoirs préalables : Tutoriel Vue.js officiel (étapes 1 à 7)

Contenu couvert :

  1. Configuration environnement (15 min)

    • Reconnexion WebStorm/GitHub (token)
    • Vérification Git et terminal
  2. Création projet Vuetify (30 min)

    • Commande npm create vuetify
    • Preset "Everything" (toutes les options)
    • Choix JavaScript (pas TypeScript pour débutants)
    • Installation dépendances avec npm
    • Explication npm et npmjs.com
  3. Lancement et outils (20 min)

    • Lancement serveur npm run dev
    • Installation Vue DevTools (Firefox/Brave)
    • Inspection des composants
  4. Structure projet Vue.js (30 min)

    • Dossier public/ : fichiers statiques (favicon, images)
    • Dossier src/ : fichiers traités par Vue.js
    • Flux de démarrage : index.html → main.js → App.vue
    • Hot Reload (rechargement automatique)
  5. Bases Vue.js - Pratique (60 min)

    • Modification App.vue
    • Variables réactives avec ref()
    • Interpolation
    • Directive v-model (liaison bidirectionnelle)
    • Directive v-bind (liaison d'attributs)
  6. Configuration ESLint (15 min)

    • Fichier eslint.config.js
    • Activer "Run eslint --fix on save" dans WebStorm
    • Formatage automatique du code

Reporté à la séance 3 :

  • Publication sur GitHub
  • Hébergement Infomaniak
  • Correction tutoriel Vue.js (étapes 1-7)

Ressources :

Séance 3 - 4 février 2026 ✓

Thème : Bases de Vue.js et début Infomaniak

Objectifs :

  • Approfondir les bases de Vue.js en codant ensemble
  • Distribuer les exercices pratiques
  • Démarrer la configuration Infomaniak

Devoirs préalables : Relire le tutoriel Vue.js (étapes 1 à 7)

Contenu :

  1. Rappels et démarrage projet (15 min)

    • Démarrer le serveur (npm run dev ou panneau NPM WebStorm)
    • Ouvrir la console du navigateur (débogage)
    • Vue DevTools pour inspecter les composants
  2. Demo Vue.js - Coder ensemble (90 min)

    • Rappel structure composant : <script>, <template>, <style>Anatomie d'une application
    • Flux de démarrage : index.html → main.js → App.vue
    • Variables réactives ref() et .value
    • Interpolation et v-model
    • Événements @click et fonctions
    • Raccourci clavier @keyup.enter
    • Références d'éléments useTemplateRef() pour le focus
    • Propriétés calculées computed() pour filtrer un tableau
    • Checkbox avec v-model (booléen)
    • Débogage : console, messages d'erreur, ligne/caractère
  3. Distribution exercices "Bases de Vue.js" (30 min)

    • Exercices via GitHub Classroom
    • Clonage du dépôt dans WebStorm (File > New > Project from Version Control)
    • npm install + npm run dev
    • Exercice 1 réalisé ensemble en classe
    • Solutions : kode.ch/vue-bases/
  4. Début configuration Infomaniak (30 min)

    • Activation compte étudiant gratuit
    • Création hébergement web et nom de domaine
    • Création utilisateur FTP

Reporté à la séance 4 :

  • Finalisation déploiement Infomaniak (workflow GitHub Actions)
  • Introduction SASS/SCSS

Ressources :

Séance 4 - 11 février 2026 ✓

Thème : Déploiement Infomaniak/Vercel et présentation du projet

Objectifs :

  • Finaliser le déploiement automatisé sur Infomaniak
  • Déployer l'application sur Vercel
  • Présenter le projet individuel

Contenu couvert :

  1. Correction exercices 1 à 4 (30 min)

  2. Présentation du projet individuel (15 min)

    • Projet Vue.js 3 avec Vuetify, Pinia et API externe
    • Système d'évaluation (30 pts projet + 50 pts oral)
    • Critères d'une bonne API (images, endpoint liste + détail, contenu riche)
    • Utilisation de Postman pour tester les APIs
    • 👉 Détails du projet
  3. Finalisation déploiement Infomaniak (~2h30)

    • Configuration compte FTP (mots de passe sécurisés)
    • Secrets GitHub (FTP_USER, FTP_PASSWORD, FTP_SERVER)
    • Workflow GitHub Actions pour déploiement automatique via tags/releases
    • Staging (GitHub Pages) vs Production (Infomaniak)
    • Dépannage individuel (configuration, erreurs de déploiement)
    • Importance de l'automatisation pour la sécurité (plus de mots de passe FTP partagés)
  4. Déploiement sur Vercel (30 min)

    • Création d'un compte Vercel par les apprentis
    • Connexion avec GitHub
    • Déploiement automatique de l'application

Reporté à la séance 5 :

  • Tutoriel Vue.js étapes 8-10 (cycle de vie, computed, watchers)
  • Exercices 5 à 7

Note : Le déploiement Infomaniak a pris beaucoup plus de temps que prévu (dépannage individuel). Pas de devoirs donnés.

Ressources :

Séance 5 - 25 février 2026 ✓

Thème : Cycle de vie & Watchers

Objectifs :

  • Comprendre le cycle de vie d'un composant
  • Découvrir les watchers (watch, watchEffect)
  • Pratiquer avec le tutoriel et les exercices

Devoirs préalables : Terminer exercices 1 à 4 (GitHub Classroom)

Contenu couvert :

  1. Rappel séance 4 (10 min)

    • Recap déploiement : CI/CD, GitHub Actions, Infomaniak, Vercel
    • Vercel pour les POC (Proof of Concept), test smartphone
    • Question technique : cloner un projet sur un autre PC (ne jamais copier un dossier Git)
  2. Présentation théorique - Cycle de vie & Watchers (30 min)

    • Cycle de vie : hooks (crochets), onMounted, onUnmounted
    • Exemples concrets : appel API avant affichage, confirmation avant perte de données
    • Skeleton loaders avec Vuetify (v-skeleton-loader)
    • Problématique scroll dans les SPA
    • Rappel computed() : cache intelligent vs fonctions
    • watch() et watchEffect() : surveiller des données réactives
    • Bonnes pratiques : computed pour données dérivées, watch pour effets
  3. Tutoriel Vue.js - Étapes 8 à 10 (travail autonome)

    • Étape 8 : Cycle de vie (onMounted, onUnmounted)
    • Étape 9 : Propriétés calculées (computed)
    • Étape 10 : Observateurs (watch, watchEffect)
  4. Exercices "Bases de Vue.js" 5 à 7 (travail autonome)

    • Exercice 5 : Computed
    • Exercice 6 : Watch
    • Exercice 7 : WatchEffect

Devoirs pour la séance 6 :

  • Terminer tout le tutoriel Vue.js officiel (étapes 1 à 15)
  • Terminer les exercices "Bases de Vue.js" 1 à 7

Ressources :

Séance 6 - 4 mars 2026 ✓

Thème : Composants Vue.js — Props, Emits & Slots

Objectifs :

  • Comprendre le découpage en composants
  • Passer des données avec les props (defineProps)
  • Communiquer via les événements (defineEmits)
  • Injecter du contenu avec les slots

Devoirs préalables :

  • Terminer tout le tutoriel Vue.js officiel (étapes 1 à 15)
  • Terminer les exercices "Bases de Vue.js" 1 à 7

Contenu couvert :

  1. Présentation théorique - Composants (~1h15)

    • Introduction aux composants : découpage, import, réutilisation
    • Lien avec le vibe coding (composants = meilleure testabilité avec l'IA)
    • Démo interactive sur le Playground Vue.js :
      • Créer un composant enfant et l'importer
      • PascalCase vs kebab-case pour les balises
      • scoped CSS : portée limitée au composant
    • Props : defineProps(), passage statique vs dynamique (:)
    • Props en lecture seule, validation avec v-if
    • Emits : defineEmits(), communication enfant → parent
    • Slots : injection de contenu HTML (défaut, nommés, valeur par défaut)
    • Exemple concret avec les slots Vuetify (v-card, v-text-field)
  2. Choix des API pour le projet personnel

    • Validation des API choisies par les apprentis
    • Vérification : gratuite, publique, avec images
  3. Travail autonome (~1h30)

    • Tutoriel Vue.js étapes 11-14 (composants)
    • Exercices "Bases de Vue.js" 8 et 9
    • Finalisation du choix d'API

Ressources :

Séance 7 - 11 mars 2026 ✓

Thème : Vuetify + API — Rick & Morty Explorer

Voir la démo en ligne | Dépôt GitHub

Objectifs :

  • Consommer une API REST et afficher des données dans Vuetify
  • Découvrir les composants Vuetify (v-card, v-img, v-chip, v-list)
  • Comprendre le routage Vue Router (2 pages, navigation drawer)

Devoirs préalables :

  • Terminer le tutoriel Vue.js (étapes 1 à 15)
  • Terminer les exercices "Bases de Vue.js" 1 à 9

Récupérer le projet Rick & Morty Explorer

Étape 1 — Créer votre copie du projet

  1. Ouvrir le dépôt template : github.com/fallinov/esig-141-demo-vuetify-api
  2. Cliquer sur le bouton vert "Use this template""Create a new repository"

Bouton "Use this template" sur GitHub

  1. Cocher "Include all branches" (pour avoir la branche solution)
  2. Repository name : esig-141-demo-vuetify-api
  3. Visibilité : Public
  4. Cliquer sur "Create repository"

Formulaire de création avec "Include all branches" coché

Étape 2 — Cloner et ouvrir dans WebStorm

  1. Copier l'URL de votre dépôt : https://github.com/VOTRE-PSEUDO/esig-141-demo-vuetify-api.git

Bouton "Code" pour copier l'URL de clonage

  1. Dans WebStorm : FileNewProject from Version Control...
  2. Coller l'URL et cliquer sur Clone
  3. Ouvrir le terminal intégré et lancer :
bash
npm install
npm run dev
  1. L'application s'ouvre sur http://localhost:3000

Contenu

  1. P1-P2 : Démo collective — Rick & Morty Explorer (~1h30)

    • Suivre le guide étape par étape (étapes 0 à 5, + bonus étape 6)
    • Appel API avec fetch() dans onMountedLes 3 états d'un appel API : loading, error, data
    • Affichage dans des v-card avec v-img, v-chip et grille responsive
    • Page statique À propos avec v-card, v-list, v-icon
    • Navigation : v-navigation-drawer avec hamburger et v-list-item :toVue Router
    • Déploiement sur Vercel
  2. P3-P4 : Mise en pratique individuelle (~1h30)

    • Créer un projet Vuetify : devjs.ch/vue/creer-app-vuetify (npm create vuetify, preset Recommended)
    • Créer un dépôt GitHub et pousser le projet
    • Rédaction du README (nom, API, description)
    • Test de l'API avec Bruno ou Postman
    • Reproduction de la démo avec leur propre API
    • Déploiement sur Vercel
    • Suivre la checklist du projet personnel en bas du guide

Objectif de fin de séance : chaque apprenti a une app Vuetify qui affiche les données brutes de son API.

Ressources :

Progression pédagogique

À partir de cette séance, chaque nouveau concept est d'abord appris via le Pokédex (exercice guidé) puis transposé dans le projet personnel (application autonome). La progression technique suit le même chemin dans les deux projets : fetch() brut → Pinia → Axios.

Séance 8 - 25 mars 2026 ✓

Thème : Setup Pokédex + Composants + Routes

Objectifs :

  • Mettre en place le projet Pokédex et consommer l'API avec fetch()
  • Découper l'interface en composants réutilisables (defineProps, defineEmits, slots)
  • Créer les pages et la navigation avec le file-based routing

Devoirs préalables : Projet personnel initialisé avec fetch() fonctionnel et liste affichée

Contenu :

  1. P1 : Setup Pokédex + fetch API (~45 min)

  2. P2 : Composants réutilisables (~45 min)

Encart oral — Props vs Emits

Props = le parent envoie des données à l'enfant (sens unique, lecture seule). Emits = l'enfant notifie le parent qu'un événement s'est produit. Analogie : les props sont un courrier recommandé (parent → enfant), les emits sont un accusé de réception (enfant → parent).

  1. P3 : Pages et navigation (~45 min)

    • Suivre E3 — Pages et navigation + E4 — Page détail
    • File-based routing : créer un fichier dans src/pages/ = créer une route
    • Créer les pages : favoris.vue, a-propos.vue, pokemon/[id].vue
    • Compléter AppHeader : menu avec v-btn :to + icônes MDI
    • Rendre PokemonCard cliquable → navigation vers /pokemon/:id
    • Page détail basique : useRoute().params.id, afficher un Pokémon
    • Bouton retour avec router.push('/')
  2. P4 : Transposition projet personnel (~45 min)

    • Suivre E5 — Récap + projet perso
    • Extraire son ItemCard.vue (ou équivalent) avec defineProps
    • Créer ses pages (liste, détail, favoris)
    • Navigation adaptée à son projet
    • Premier commit avec message clair

Checklist projet perso :

  • ≥ 3 composants avec props typées
  • ≥ 3 pages avec navigation fonctionnelle
  • Route dynamique /item/:id avec page détail
  • Commit poussé sur GitHub

Ressources :

Séance 9 - 1er avril 2026 ✓

Thème : Pinia — Centraliser les données

Objectifs :

  • Comprendre le problème du prop drilling et le rôle d'un store
  • Créer un store Pinia from scratch (state, getters, actions)
  • Utiliser storeToRefs() pour destructurer sans perdre la réactivité

Devoirs préalables : Pokédex avec composants et pages fonctionnels (résultat séance 8)

Point de départ — Branche etape-6-start

Si votre Pokédex n'est pas à jour, vous pouvez repartir de la branche etape-6-start qui contient le code solution des étapes 1 à 5 :

bash
# Ajouter le dépôt du prof (une seule fois)
git remote add prof https://github.com/fallinov/esig-141-pokedex-vuetify.git
# Récupérer les branches et basculer
git fetch prof
git checkout -b etape-6-start prof/etape-6-start
npm install

Voir la branche sur GitHub

Contenu couvert :

  1. Rappels et mise à jour (15 min)

    • Quelques absents en début de cours
    • Installation outil de gestion de classe (Leptis) — code d'activation distribué
    • Rappel de l'état attendu : Pokédex avec 3 pages (accueil, favoris, à propos), file-based routing, route dynamique [id].vue, bouton retour
    • Rappel : démarrer l'API locale (npm run dev dans pokedex-api, port 3535) avant le projet
  2. P1 : Git — Ajouter le remote du prof (15 min)

    • Explication : on peut avoir plusieurs origines (remotes) sur un dépôt Git
    • Commande : git remote add prof https://github.com/fallinov/esig-141-pokedex-vuetify.git
    • Puis git fetch prof pour récupérer toutes les branches
    • git checkout -b etape-6-start prof/etape-6-start pour repartir du bon pied
    • Vérification dans WebStorm : Remote → origin + prof visibles
    • Utile pour les absents ou ceux en retard : chaque leçon a sa branche de départ
  3. P1 : Théorie Pinia au tableau (~30 min)

    • Pourquoi un store ? : chaque composant fait son propre fetch() → duplication, incohérence
    • Schéma au tableau : avant (chaque page → API) vs après (pages → magasin → API)
    • Analogie du restaurant : le serveur (store) prend les commandes de tout le monde, pas le téléphone arabe entre convives
    • Analogie de l'escape room : le maître du jeu connaît tout, chaque joueur n'a qu'une partie de l'info
    • Quand utiliser Pinia : dès que 2+ pages partagent les mêmes données, ou dès qu'il y a du prop drilling sur 2+ niveaux
    • Anatomie d'un store — 3 parties :
      • State = données (ref()) → pokemons, types, isLoading, error
      • Getters = données calculées (computed()) → totalPokemons, getPokemonById(id)
      • Actions = fonctions → fetchPokemons(), fetchTypes(), init()
    • Règle : toujours initialiser le state avec des valeurs par défaut (tableau vide, false, null)
    • Les getters ne modifient jamais les données, ils les retournent sous un autre format
  4. P1-P2 : Live coding — Créer pokemonStore.js (~45 min)

    • Créer src/stores/pokemonStore.js — Click droit → New → JavaScript file
    • import { defineStore } from 'pinia'
    • defineStore('pokemon', { state, getters, actions })
    • State : pokemons: [], types: [], isLoading: true, error: null
    • Getter totalPokemons : (state) => state.pokemons.length — rappel syntaxe arrow function (raccourci sans accolades ni return)
    • Getter getPokemonById : utilise state.pokemons.find() — retourne une fonction
    • Action fetchPokemons : async, await fetch(...), test response.ok, throw new Error, this.pokemons = await response.json() — rappel this pour accéder au state dans les actions
    • Action fetchTypes : copier-coller de fetchPokemons, adapter URL et state cible
    • Action init : try/catch/finally, this.isLoading = true, await Promise.all([this.fetchPokemons(), this.fetchTypes()]), finally this.isLoading = false
    • Explication Promise.all : lance les 2 requêtes en parallèle, attend que les 2 aient répondu (plus efficace que 2 await séquentiels)
    • Digression : IDs modernes sont des UUID (pas des séquences 1, 2, 3 comme en Oracle), générés par algorithme, quasi-uniques
    • Commit sur branche étape-6
  5. P2 : Live coding — Connecter le store (~30 min)

    • App.vue : import usePokemonStore, const pokemonStore = usePokemonStore(), onMounted(() => pokemonStore.init())
    • Vérification dans Vue DevTools → onglet Pinia : le magasin Pokémon apparaît avec toutes les données
    • index.vue : supprimer l'ancien fetch() local, remplacer par le store
    • Démo sans storeToRefs : destructuration classique const { pokemons } = usePokemonStore() → ça affiche les pokémons mais perd la réactivité → supprimer un pokémon dans DevTools → l'UI ne change pas
    • Démo avec storeToRefs : const { pokemons } = storeToRefs(usePokemonStore()) → supprimer/modifier un pokémon dans DevTools → l'UI se met à jour instantanément
    • Explication de la destructuration JS (const { pokemons } = obj est un raccourci pour const pokemons = obj.pokemons)
    • Aperçu localStorage pour les favoris (séance 12)
    • Commit
  6. P3-P4 : Travail autonome (~1h30)

Observations :

  • La majorité des élèves étaient à jour avec l'exercice et le projet perso
  • Le live coding collectif a pris plus de temps que prévu (P1 entière + début P2)
  • Les élèves ont voté pour faire ensemble plutôt que seuls
  • Le concept de storeToRefs a bien fonctionné grâce à la démo avant/après dans DevTools

Checklist projet perso :

  • Store Pinia créé avec state, ≥ 1 getter, ≥ 1 action
  • storeToRefs() utilisé dans les composants
  • fetch() migré du composant vers le store
  • Pages connectées au store
  • Commit poussé sur GitHub

Ressources :

Séance 10 - 22 avril 2026 ✓

Thème : Axios, variables d'environnement et robustesse API

Objectifs :

  • Comprendre les limites de fetch() brut et l'intérêt d'Axios
  • Configurer une instance Axios avec axios.create()
  • Utiliser les variables d'environnement (.env, VITE_API_URL)
  • Gérer les 3 états d'un appel API (loading, error, data)

Devoirs préalables : Store Pinia fonctionnel avec fetch()

Point de départ — Branche etape-9-start

Si votre Pokédex n'est pas à jour, vous pouvez repartir de la branche etape-9-start qui contient le code solution des étapes précédentes :

bash
# Ajouter le dépôt du prof (une seule fois)
git remote add prof https://github.com/fallinov/esig-141-pokedex-vuetify.git
# Récupérer les branches et basculer
git fetch prof
git checkout -b etape-9-start prof/etape-9-start
npm install

Voir la branche sur GitHub

Contenu couvert :

  1. P1 : Migration fetch → Axios (~30 min)

    • Live coding : remplacement de fetch() par api.get() dans le store
    • Configuration de l'instance Axios avec axios.create() + variable VITE_API_URL
  2. P2 : Gestion des images manquantes avec v-img (~15 min)

    • Question d'élève : que faire quand les images ne chargent pas ?
    • Découverte dans la doc Vuetify : v-slot:error et v-slot:placeholder sur v-img
    • Live coding : ajout d'un <template #error> dans PokemonCard avec une image par défaut
  3. P3 : Travail autonome (~45 min)

    • Les élèves migrent leur store de fetch() vers Axios sur leur projet perso
    • Aide individuelle (debugging Axios, structure du store)
  4. P4 : Démo Vercel (~20 min)

    • Vercel vs GitHub Pages vs Infomaniak : Vercel analyse l'app automatiquement, pas de config
    • Visualisation des branches déployées sur Vercel
    • Erreur de build : un fichier non commité causait une erreur → toujours faire npm run build en local avant de pousser

Reporté à la séance 11 :

  • v-skeleton-loader (loading state) et v-alert (error state)
  • Exercices E9, E10, E11

Observations :

  • Axios et .env étaient déjà configurés par certains élèves depuis la séance 9
  • Vercel a pris du temps (debugging individuel)

Checklist projet perso :

  • Axios installé et configuré avec axios.create()
  • .env avec VITE_API_URL + .env.example
  • .env dans .gitignore
  • fetch() remplacé par axios.get() dans le store
  • Commit poussé sur GitHub

Ressources :

Séance 11 - 29 avril 2026 ✓

Thème : Recherche, filtre et tri

Note historique — édition 2025-2026

P1 (mock local + Vercel) fait en démo collective. Pour P2 et P3, les apprentis ont préféré travailler en autonomie sans démo collective afin de transposer plus rapidement dans leur projet personnel.

Bugs Vercel découverts pendant le cours et documentés le jour même : voir Déployer sur Vercel (VITE_BASE_URL + vercel.json).

Le mock local a été retiré du cours suite à cette séance — concept dispensable, charge cognitive trop élevée.

Objectifs :

  • Utiliser computed() pour filtrer et trier sans modifier les données source
  • Chaîner les computed (recherche → filtre → tri)
  • Implémenter un filtre par catégorie/type

Devoirs préalables : Axios configuré, fetch() migré vers Axios dans le store

Point de départ — Branche etape-12-start

Si votre Pokédex n'est pas à jour, vous pouvez repartir de la branche etape-12-start qui contient le code solution des étapes précédentes :

bash
# Ajouter le dépôt du prof (une seule fois)
git remote add prof https://github.com/fallinov/esig-141-pokedex-vuetify.git
# Récupérer les branches et basculer
git fetch prof
git checkout -b etape-12-start prof/etape-12-start
npm install

Voir la branche sur GitHub

Contenu :

  1. P1 : Loading/erreurs + Vercel (~45 min)

    • Revue de code E10 (~10 min) — déjà intégré dans etape-12-start, pas de live coding
      • Ouvrir src/plugins/axios.js, src/pages/index.vue avec les apprentis
      • Repérer v-skeleton-loader (loading) + v-alert (erreur)
      • Les 3 états d'un appel API : loading, error, data
    • Démo Vercel (~35 min)
      • Push sur GitHub → Vercel redéploie automatiquement
      • Variables d'environnement sur Vercel : Settings → Environment VariablesVITE_API_URL avec l'URL de l'API
      • Pièges fréquents : voir Déployer sur Vercel (VITE_BASE_URL, vercel.json rewrite SPA)
      • Les apprentis vérifient que leur projet est bien déployé sur Vercel
  2. P2 : Pokédex — Recherche (~45 min, travail autonome)

    • Suivre E12 — Recherche par nom
    • computed() : filtre les données sans les modifier (données source intactes)
    • v-model sur v-text-field pour la recherche en temps réel
    • Array.filter() + String.includes() + toLowerCase()
    • Pokédex : recherche par nom de Pokémon
    • v-alert "Aucun résultat trouvé" si la liste filtrée est vide
  3. P3 : Pokédex — Filtre par type et tri (~45 min, travail autonome)

    • Suivre E13 — Filtre par type + tri
    • Filtre par type : v-select avec les types disponibles
    • Utiliser pokemonStore.types comme source du v-select
    • Chaîner les computed : filtre type → recherche → tri
    • Tri alphabétique / numérique : Array.sort(), localeCompare()
    • v-btn avec toggleSort() pour inverser l'ordre de tri
  4. P4 : Transposition projet personnel (~45 min)

    • Suivre E14 — Récap + projet perso
    • Recherche par texte (nom, titre, etc.)
    • Filtre par catégorie/type propre à son API
    • Tri pertinent pour ses données (alphabétique, date, note, etc.)
    • Commit

Checklist projet perso :

  • Recherche par texte fonctionnelle
  • Filtre par catégorie/type avec v-select
  • Tri (au moins 2 options)
  • Message "Aucun résultat" si liste vide
  • Commit poussé sur GitHub

Pièges connus / à anticiper :

  • sort() mute : sans [...arr].sort(), le tableau d'origine est modifié → recherche cassée la fois suivante.
  • includes() casse : oublier .toLowerCase() des deux côtés (query ET nom).
  • v-select types vide : si pokemonStore.types n'est pas encore chargé, le select est vide — vérifier que init() charge les types avant d'autoriser le filtre.
  • Vercel cache : modif .env Vercel → forcer le redéploiement (Settings → Deploy → Redeploy).
  • Où initialiser le store ? Question fréquente : l'appel init() se fait dans App.vue (une seule fois au démarrage), pas dans chaque page. Si l'appel est dans une page, les données sont perdues à chaque navigation.

Ressources :

Séance 12 - 6 mai 2026 ✓

Thème : Favoris et persistance

Note historique — édition 2025-2026

P1 + P2 faits en démo collective. localStorage démontré en live (ouverture/fermeture navigateur, onglet Stockage DevTools), JSON.stringify/parse expliqué. .stop.prevent expliqué avec la métaphore du bubbling. Transition projet personnel en P3-P4 — ambiance positive.

Objectifs :

  • Implémenter un système de favoris avec toggle
  • Persister les données avec localStorage
  • Créer une page dédiée aux favoris

Devoirs préalables : Recherche, filtre et tri fonctionnels

Point de départ — Branche etape-15-start

Si votre Pokédex n'est pas à jour, vous pouvez repartir de la branche etape-15-start qui contient le code solution des étapes précédentes :

bash
# Ajouter le dépôt du prof (une seule fois)
git remote add prof https://github.com/fallinov/esig-141-pokedex-vuetify.git
# Récupérer les branches et basculer
git fetch prof
git checkout -b etape-15-start prof/etape-15-start
npm install

Voir la branche sur GitHub

Contenu :

  1. P1 : Théorie + Pokédex — Favoris dans le store (~45 min)
    • Suivre E15 — Favoris dans le store
    • localStorage : setItem, getItem, removeItem, JSON.parse/stringify
    • Pattern toggle : ajouter si absent, retirer si présent
    • Pokédex : ajouter au store pokemonStore :
      • State : favorites (tableau d'IDs)
      • Action : toggleFavorite(pokemon) — ajoute/retire l'ID + sauvegarde localStorage
      • Getter : isFavorite(pokemon) — retourne true/false
      • Getter : getFavorites — retourne les objets Pokémon complets des favoris
      • Actions : loadFavorites() / saveFavorites() — lecture/écriture localStorage

Encart oral — localStorage

localStorage stocke des chaînes de caractères uniquement. Pour stocker un tableau ou un objet : JSON.stringify() à l'écriture, JSON.parse() à la lecture. Les données persistent même après fermeture du navigateur (contrairement à sessionStorage).

  1. P2 : Pokédex — UI favoris (~45 min)

    • Suivre E16 — Interface favoris
    • Icône cœur conditionnelle sur PokemonCard (mdi-heart / mdi-heart-outline)
    • @click.stop.prevent sur l'icône : .stop stoppe la propagation vers v-card, .prevent empêche le router-link sous-jacent
    • Créer la page favoris.vue : réutiliser PokemonCard avec getFavorites
    • v-alert "Pas encore de favoris" si la liste est vide + bouton vers l'accueil
    • Correction collective
  2. P3-P4 : Transposition projet personnel (~1h30)

    • Suivre E17 — Récap + projet perso
    • Ajouter les favoris dans son store (state, actions, getters)
    • Icône toggle sur sa carte
    • Page ou section dédiée aux favoris
    • Tester : ajouter des favoris, recharger la page → ils persistent
    • Commit

Checklist projet perso :

  • toggleFavorite() dans le store
  • Icône conditionnelle sur la carte (favori oui/non)
  • Page favoris fonctionnelle
  • Favoris persistants après rechargement (localStorage)
  • Commit poussé sur GitHub

Pièges connus / à anticiper :

  • JSON.parse(null) : si la clé n'existe pas encore en localStorage, getItem() retourne nullJSON.parse(null) retourne null. Initialiser avec || [].
  • Oublier JSON.stringify : stocker un tableau sans sérialisation → "[object Object]" en localStorage, silencieux et difficile à déboguer.
  • Comparer les IDs, pas les objets : isFavorite doit faire favorites.includes(pokemon.id), pas favorites.includes(pokemon).
  • @click.stop.prevent (les deux) : .stop stoppe la propagation vers v-card, .prevent empêche le comportement par défaut du router-link sous-jacent. L'un sans l'autre ne suffit pas.
  • Ordre dans init() : loadFavorites() doit être appelé après fetchPokemons() pour que getFavorites puisse croiser les IDs avec les objets chargés.

Ressources :

Séance 13 - 13 mai 2026

Thème : Formulaires, authentification et suppression

🎯 Kahoot révision mi-parcours en fin de séance — ne pas oublier ! (ref/reactive, computed, Pinia, .env, Vue Router, props/emits)

Objectifs :

  • Créer un formulaire avec validation (v-form, :rules)
  • Envoyer des données à l'API (POST, DELETE avec Axios)
  • Comprendre l'authentification et la protection de routes (démo)
  • 🎯 Kahoot révision mi-parcours (15 min)

Concepts avancés — Démo uniquement

Les formulaires, l'authentification et la suppression sont présentés pour compléter la culture technique et préparer l'oral. Ils ne sont pas requis dans le projet personnel.

Devoirs préalables : Favoris fonctionnels avec persistance

Point de départ — Branche etape-18-start

Si votre Pokédex n'est pas à jour, vous pouvez repartir de la branche etape-18-start qui contient le code solution des étapes précédentes :

bash
# Ajouter le dépôt du prof (une seule fois)
git remote add prof https://github.com/fallinov/esig-141-pokedex-vuetify.git
# Récupérer les branches et basculer
git fetch prof
git checkout -b etape-18-start prof/etape-18-start
npm install

Voir la branche sur GitHub

Contenu :

  1. P1 : Pokédex — Formulaire d'ajout (~45 min)

    • Suivre E18 — Formulaire d'ajout
    • v-form avec @submit.prevent
    • Champs : v-text-field, v-textarea, v-select, v-checkbox
    • Validation avec :rules (champ requis, longueur min/max, format)
    • Action addPokemon(data) dans le store → axios.post()
    • v-snackbar de confirmation après ajout réussi
    • Redirection vers l'accueil avec router.push('/')
  2. P2 : Pokédex — Authentification (~45 min)

    • Suivre E19 — Authentification + guards
    • Créer stores/authStore.js (login/logout simulé, isAuthenticated)
    • Page login : formulaire email + mot de passe avec validation
    • Protection de routes : router.beforeEach() — guard de navigation (section 5 de la doc)
    • Affichage conditionnel dans le menu (v-if sur isAuthenticated)

Encart oral — Guards de navigation

Un guard est comme un videur : il vérifie une condition avant de laisser entrer sur une page. router.beforeEach((to) => { ... }) s'exécute avant chaque navigation. Si la condition échoue, on redirige vers /login.

  1. P3 : Pokédex — Suppression (~45 min)

    • Suivre E20 — Suppression
    • Bouton supprimer visible uniquement si connecté (v-if="authStore.isAuthenticated")
    • v-dialog de confirmation avant suppression
    • Action deletePokemon(id) dans le store → axios.delete()
    • v-snackbar de confirmation + retour à l'accueil
    • Correction collective
  2. P4 : Projet personnel — Avancement libre (~45 min)

    • Avancer le projet (rattrapage, polish, fonctionnalités manquantes)
    • Aide individuelle

🎯 Kahoot révision mi-parcours (15 min en fin de séance) : ref vs reactive, computed, Pinia, .env, Vue Router, props/emits

Ressources :

Séance 14 - 20 mai 2026

Thème : UX, responsive et finalisation du projet

Objectifs :

  • Rendre l'application responsive et professionnelle
  • Personnaliser le thème Vuetify
  • Finaliser le projet personnel (README, déploiement, polish)

Devoirs préalables : Projet personnel avec toutes les fonctionnalités de base (liste, détail, recherche, filtre, tri, favoris)

Point de départ — Branche etape-22-start

Si votre Pokédex n'est pas à jour, vous pouvez repartir de la branche etape-22-start qui contient le code solution des étapes précédentes :

bash
# Ajouter le dépôt du prof (une seule fois)
git remote add prof https://github.com/fallinov/esig-141-pokedex-vuetify.git
# Récupérer les branches et basculer
git fetch prof
git checkout -b etape-22-start prof/etape-22-start
npm install

Voir la branche sur GitHub

Contenu :

  1. P1 : Pokédex — Responsive et thème (~45 min)

    • Suivre E22 — Navigation responsive + E23 — Thème + détail enrichi
    • Navigation drawer responsive : v-navigation-drawer + hamburger sur mobile
    • Breakpoints Vuetify (xs, sm, md, lg, xl) et v-col adaptatif
    • Personnalisation du thème dans plugins/vuetify.js (couleurs primary, secondary)
    • Page détail enrichie : chips de types colorés, barres de stats, grande image
    • Favicon + titre personnalisés dans index.html
  2. P2 : Démo — Transformer une web app en application mobile (~45 min)

    • Introduction : native vs hybride vs PWA
    • Démo live PWA : transformer le Pokédex en application installable
      • Ajouter vite-plugin-pwa (5 min de config)
      • Configurer le manifest (nom, icônes, couleurs)
      • Builder et tester : installer l'app depuis le navigateur sur mobile
    • Résultat : l'app s'installe comme une vraie application, fonctionne hors ligne
    • Alternative mentionnée : Capacitor (Ionic) pour un vrai APK Android/iOS

Pas requis dans le projet personnel

La PWA est une démonstration pour montrer les possibilités. Ce n'est pas évalué dans le projet personnel, mais c'est un plus si vous le faites.

  1. P3-P4 : Finalisation projet personnel (~1h30)
    • Design personnel : couleurs, typographie, icônes
    • Navigation responsive (drawer ou menu adaptatif)
    • Feedback UX : loading, erreurs, snackbar
    • README.md complet : description, installation, API, captures d'écran
    • Vérifier .env.example, .gitignore
    • Déploiement sur Vercel ou GitHub Pages
    • Tester sur mobile (responsive)
    • 0 erreurs console
    • Dernier commit + push

🎯 Kahoot préparation oral (15 min en fin de séance) : questions types de l'examen oral

Checklist finale projet perso :

  • Application déployée et fonctionnelle (URL en ligne)
  • Page d'accueil avec liste/grille
  • Page de détail avec route dynamique :id
  • Navigation fonctionnelle (header ou drawer)
  • Recherche par texte
  • Filtre par catégorie/type
  • Tri (au moins 2 options)
  • Système de favoris persistants (localStorage)
  • Feedback utilisateur (snackbar, loading, erreurs)
  • Design responsive (testé mobile + desktop)
  • Store Pinia (state, getters, actions)
  • Axios configuré avec .env
  • .env.example présent (sans secrets)
  • README.md complet avec captures d'écran
  • Commits réguliers avec messages clairs
  • 0 erreurs dans la console

Ressources :

Séance 15 - 27 mai 2026

Rendu du projet + Examen oral

Rendu du projet :

  • Application en ligne (Vercel ou GitHub Pages)
  • Dépôt GitHub propre et structuré
  • README.md complet

Préparation orale (début de séance) :

  • Relire son code (comprendre chaque fonction)
  • Préparer la démo (2-3 min, parcours utilisateur)
  • Lister les améliorations possibles
  • Simulation d'oral en binôme

Examen oral (3 juin après-midi) :

  • Démo de l'application : 2-3 min
  • Présentation des améliorations possibles
  • Questions théoriques : 3 questions × 6 pts = 18 pts
  • Questions pratiques (sur le code) : 3 questions × 9 pts = 27 pts
  • Durée : ~20 min par candidat

Ressources :

Récapitulatif des compétences

CompétenceSéances
Vue.js 3 — Composition API1-6
Composants (props, emits, slots)6, 8
Déploiement (GitHub Pages, Infomaniak, Vercel)4, 7, 14
Vuetify — Material Design7-14
File-based routing (Vue Router)8-14
Appel API (fetch)7-9
Pinia — State management9-14
Appel API (Axios, .env)10-14
Recherche, filtre, tri (computed)11-14
Favoris et persistance (localStorage)12-14
Formulaires et validation13
Authentification et guards13
CRUD complet (POST, DELETE)13
UX, responsive, theming14
PWA — App mobile (démo)14
Projet personnel (API externe)7-15

Documentation pour les cours de développement web