644 lines
12 KiB
Markdown
644 lines
12 KiB
Markdown
# Guide de Développement - Application Binôme (Stack Moderne)
|
|
|
|
## 🚀 Vue d'Ensemble
|
|
|
|
L'application **Binôme** est maintenant basée sur une stack moderne Vue 3 + Vite + Pinia, optimisée pour le développement et la performance.
|
|
|
|
### Stack Technique
|
|
|
|
- **Frontend** : Vue 3.5.17 + TypeScript
|
|
- **Build Tool** : Vite 7.0.5
|
|
- **State Management** : Pinia 3.0.3 avec persistence
|
|
- **Routing** : Vue Router 4.5.1
|
|
- **Styling** : SCSS avec variables globales
|
|
- **PWA** : vite-plugin-pwa
|
|
- **Package Manager** : pnpm
|
|
- **Node.js** : v20 (LTS)
|
|
|
|
---
|
|
|
|
## 🛠️ Prérequis et Installation
|
|
|
|
### Prérequis Système
|
|
|
|
```bash
|
|
# Node.js version 20 (LTS)
|
|
node --version # doit afficher v20.x.x
|
|
|
|
# pnpm installé globalement
|
|
npm install -g pnpm@latest
|
|
```
|
|
|
|
### Installation du Projet
|
|
|
|
```bash
|
|
# Cloner le projet
|
|
git clone <repository-url>
|
|
cd binome
|
|
|
|
# Installer les dépendances
|
|
pnpm install
|
|
|
|
# Vérifier l'installation
|
|
pnpm dev
|
|
```
|
|
|
|
---
|
|
|
|
## 📜 Scripts Disponibles
|
|
|
|
### Scripts de Développement
|
|
|
|
```bash
|
|
# Démarrer le serveur de développement
|
|
pnpm dev
|
|
# → Lance Vite dev server sur http://localhost:8080
|
|
# → Hot Module Replacement (HMR) activé
|
|
# → Ouverture automatique du navigateur
|
|
|
|
# Prévisualiser la build de production
|
|
pnpm preview
|
|
# → Sert la version buildée localement
|
|
# → Utile pour tester avant déploiement
|
|
```
|
|
|
|
### Scripts de Build
|
|
|
|
```bash
|
|
# Build de production
|
|
pnpm build
|
|
# → Génère le dossier /dist optimisé
|
|
# → Minification et tree-shaking automatiques
|
|
# → Source maps incluses
|
|
|
|
# Analyser la build
|
|
pnpm build --analyze
|
|
# → Affiche la taille des bundles
|
|
# → Identifie les dépendances lourdes
|
|
```
|
|
|
|
### Scripts de Qualité
|
|
|
|
```bash
|
|
# Linter ESLint
|
|
pnpm lint
|
|
# → Vérifie et corrige automatiquement le code
|
|
# → Supporte .vue, .ts, .js files
|
|
# → Configuration dans .eslintrc.js
|
|
|
|
# Type checking TypeScript
|
|
pnpm type-check
|
|
# → Vérifie les types sans compilation
|
|
# → Utile en CI/CD
|
|
```
|
|
|
|
---
|
|
|
|
## 🏗️ Architecture du Projet
|
|
|
|
### Structure des Dossiers
|
|
|
|
```
|
|
src/
|
|
├── assets/ # Ressources statiques (SVG, images)
|
|
├── components/ # Composants Vue réutilisables
|
|
│ ├── ChilledMusic.vue
|
|
│ ├── DevSession.vue
|
|
│ ├── IntervalInput.vue
|
|
│ ├── SpotifyMusic.vue
|
|
│ ├── SWNewVersion.vue
|
|
│ └── ZoneMusic.vue
|
|
├── hooks/ # Composables Vue 3
|
|
│ ├── useInterval.ts
|
|
│ ├── useMusic.ts
|
|
│ ├── useSpotify.ts
|
|
│ ├── useTimer.ts
|
|
│ └── useWakeLock.ts
|
|
├── lib/ # Bibliothèques externes
|
|
│ └── spotify-player.js # ⚠️ CRITIQUE - Ne pas modifier
|
|
├── locales/ # Fichiers de traduction i18n
|
|
│ ├── en.json
|
|
│ └── fr.json
|
|
├── router/ # Configuration Vue Router
|
|
│ └── index.ts
|
|
├── store/ # Store Pinia
|
|
│ └── index.ts
|
|
├── styles/ # Styles SCSS globaux
|
|
│ ├── app.scss
|
|
│ ├── plume.scss
|
|
│ └── variables.scss
|
|
├── types/ # Types TypeScript
|
|
│ └── StopwatchState.ts
|
|
├── utils/ # Utilitaires
|
|
│ ├── notification.ts
|
|
│ └── spotify.ts
|
|
├── views/ # Pages/Vues principales
|
|
│ ├── Home.vue
|
|
│ ├── Privacy.vue
|
|
│ └── SpotifyCallback.vue
|
|
├── App.vue # Composant racine
|
|
├── i18n.ts # Configuration internationalisation
|
|
└── main.ts # Point d'entrée de l'application
|
|
```
|
|
|
|
---
|
|
|
|
## 🎯 Patterns de Développement
|
|
|
|
### 1. Composants Vue 3
|
|
|
|
#### Composition API avec `<script setup>`
|
|
|
|
```vue
|
|
<template>
|
|
<div class="my-component">
|
|
<h2>{{ title }}</h2>
|
|
<button @click="increment">Count: {{ count }}</button>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref } from 'vue'
|
|
|
|
// Props avec TypeScript
|
|
interface Props {
|
|
title: string
|
|
initialCount?: number
|
|
}
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
initialCount: 0
|
|
})
|
|
|
|
// État réactif
|
|
const count = ref(props.initialCount)
|
|
|
|
// Méthodes
|
|
const increment = () => {
|
|
count.value++
|
|
}
|
|
|
|
// Émissions d'événements
|
|
const emit = defineEmits<{
|
|
countChanged: [value: number]
|
|
}>()
|
|
|
|
// Watcher
|
|
watch(count, (newValue) => {
|
|
emit('countChanged', newValue)
|
|
})
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.my-component {
|
|
padding: 1rem;
|
|
border: 1px solid $primary-color; // Variable SCSS globale
|
|
}
|
|
</style>
|
|
```
|
|
|
|
#### Composables (Hooks Personnalisés)
|
|
|
|
```typescript
|
|
// hooks/useCounter.ts
|
|
import { ref, computed } from 'vue'
|
|
|
|
export function useCounter(initialValue = 0) {
|
|
const count = ref(initialValue)
|
|
|
|
const increment = () => count.value++
|
|
const decrement = () => count.value--
|
|
const reset = () => count.value = initialValue
|
|
|
|
const isEven = computed(() => count.value % 2 === 0)
|
|
|
|
return {
|
|
count: readonly(count),
|
|
increment,
|
|
decrement,
|
|
reset,
|
|
isEven
|
|
}
|
|
}
|
|
```
|
|
|
|
### 2. Store Pinia
|
|
|
|
#### Définition du Store
|
|
|
|
```typescript
|
|
// store/modules/timer.ts
|
|
import { defineStore } from 'pinia'
|
|
|
|
interface TimerState {
|
|
currentTime: number
|
|
isRunning: boolean
|
|
interval: number
|
|
}
|
|
|
|
export const useTimerStore = defineStore('timer', {
|
|
state: (): TimerState => ({
|
|
currentTime: 0,
|
|
isRunning: false,
|
|
interval: 5
|
|
}),
|
|
|
|
getters: {
|
|
formattedTime: (state) => {
|
|
const minutes = Math.floor(state.currentTime / 60)
|
|
const seconds = state.currentTime % 60
|
|
return `${minutes}:${seconds.toString().padStart(2, '0')}`
|
|
}
|
|
},
|
|
|
|
actions: {
|
|
startTimer() {
|
|
this.isRunning = true
|
|
},
|
|
|
|
stopTimer() {
|
|
this.isRunning = false
|
|
},
|
|
|
|
resetTimer() {
|
|
this.currentTime = 0
|
|
this.isRunning = false
|
|
}
|
|
},
|
|
|
|
// Persistence automatique
|
|
persist: {
|
|
key: 'timer-store',
|
|
storage: localStorage,
|
|
paths: ['interval'] // Seuls certains champs
|
|
}
|
|
})
|
|
```
|
|
|
|
#### Utilisation dans les Composants
|
|
|
|
```vue
|
|
<script setup lang="ts">
|
|
import { useTimerStore } from '@/store'
|
|
|
|
const timerStore = useTimerStore()
|
|
|
|
// Accès direct aux propriétés réactives
|
|
const { currentTime, isRunning, formattedTime } = storeToRefs(timerStore)
|
|
|
|
// Accès aux actions
|
|
const { startTimer, stopTimer, resetTimer } = timerStore
|
|
</script>
|
|
```
|
|
|
|
### 3. Internationalisation (i18n)
|
|
|
|
#### Utilisation dans les Composants
|
|
|
|
```vue
|
|
<template>
|
|
<div>
|
|
<h1>{{ $t('welcome.title') }}</h1>
|
|
<p>{{ $t('welcome.message', { name: userName }) }}</p>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { useI18n } from 'vue-i18n'
|
|
|
|
const { t, locale } = useI18n()
|
|
|
|
// Changement de langue
|
|
const switchLanguage = (lang: string) => {
|
|
locale.value = lang
|
|
}
|
|
</script>
|
|
```
|
|
|
|
#### Ajout de Nouvelles Traductions
|
|
|
|
```json
|
|
// locales/fr.json
|
|
{
|
|
"welcome": {
|
|
"title": "Bienvenue dans Binôme",
|
|
"message": "Bonjour {name}, prêt pour une session de programmation ?"
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🎨 Styling et Thèmes
|
|
|
|
### Variables SCSS Globales
|
|
|
|
```scss
|
|
// styles/variables.scss
|
|
$primary-color: #f8efba;
|
|
$secondary-color: #333;
|
|
$font-family: 'Arial', sans-serif;
|
|
$border-radius: 8px;
|
|
$spacing-unit: 1rem;
|
|
|
|
// Breakpoints
|
|
$mobile: 768px;
|
|
$tablet: 1024px;
|
|
$desktop: 1200px;
|
|
```
|
|
|
|
### Utilisation dans les Composants
|
|
|
|
```vue
|
|
<style lang="scss" scoped>
|
|
.component {
|
|
background-color: $primary-color;
|
|
padding: $spacing-unit;
|
|
border-radius: $border-radius;
|
|
|
|
@media (max-width: $mobile) {
|
|
padding: $spacing-unit / 2;
|
|
}
|
|
}
|
|
</style>
|
|
```
|
|
|
|
---
|
|
|
|
## 🔧 Configuration de Développement
|
|
|
|
### Vite Configuration ([`vite.config.ts`](vite.config.ts:1))
|
|
|
|
```typescript
|
|
import { defineConfig } from 'vite'
|
|
import vue from '@vitejs/plugin-vue'
|
|
import { VitePWA } from 'vite-plugin-pwa'
|
|
|
|
export default defineConfig({
|
|
plugins: [
|
|
vue(),
|
|
VitePWA({
|
|
registerType: 'autoUpdate',
|
|
workbox: {
|
|
skipWaiting: true,
|
|
clientsClaim: true
|
|
}
|
|
})
|
|
],
|
|
|
|
resolve: {
|
|
alias: {
|
|
'@': resolve(__dirname, 'src')
|
|
}
|
|
},
|
|
|
|
server: {
|
|
port: 8080,
|
|
open: true,
|
|
hmr: true
|
|
}
|
|
})
|
|
```
|
|
|
|
### TypeScript Configuration
|
|
|
|
```json
|
|
// tsconfig.json
|
|
{
|
|
"compilerOptions": {
|
|
"target": "esnext",
|
|
"module": "esnext",
|
|
"moduleResolution": "node",
|
|
"strict": true,
|
|
"paths": {
|
|
"@/*": ["src/*"]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🧪 Tests et Qualité
|
|
|
|
### ESLint Configuration
|
|
|
|
```javascript
|
|
// .eslintrc.js
|
|
module.exports = {
|
|
extends: [
|
|
'plugin:vue/vue3-essential',
|
|
'eslint:recommended',
|
|
'@vue/typescript/recommended'
|
|
],
|
|
rules: {
|
|
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off'
|
|
}
|
|
}
|
|
```
|
|
|
|
### Commandes de Vérification
|
|
|
|
```bash
|
|
# Vérification complète avant commit
|
|
pnpm lint && pnpm type-check && pnpm build
|
|
```
|
|
|
|
---
|
|
|
|
## 📱 PWA et Service Worker
|
|
|
|
### Configuration PWA
|
|
|
|
L'application est configurée comme PWA avec :
|
|
|
|
- **Manifest** : Icônes, couleurs, mode d'affichage
|
|
- **Service Worker** : Cache automatique, mise à jour en arrière-plan
|
|
- **Raccourcis** : Accès rapide aux fonctionnalités
|
|
|
|
### Gestion des Mises à Jour
|
|
|
|
```vue
|
|
<!-- components/SWNewVersion.vue -->
|
|
<template>
|
|
<div v-if="needRefresh" class="update-banner">
|
|
<p>{{ $t('notification.update.body') }}</p>
|
|
<button @click="updateSW">{{ $t('update') }}</button>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { useRegisterSW } from 'virtual:pwa-register/vue'
|
|
|
|
const { needRefresh, updateServiceWorker } = useRegisterSW()
|
|
|
|
const updateSW = async () => {
|
|
await updateServiceWorker()
|
|
}
|
|
</script>
|
|
```
|
|
|
|
---
|
|
|
|
## 🎵 Intégration Spotify
|
|
|
|
### Fichier Critique : [`spotify-player.js`](src/lib/spotify-player.js:1)
|
|
|
|
⚠️ **ATTENTION** : Ce fichier ne doit JAMAIS être modifié
|
|
|
|
- Contient le SDK Spotify personnalisé
|
|
- 571 lignes de code critique
|
|
- Toute modification peut casser l'intégration Spotify
|
|
|
|
### Utilisation du Player Spotify
|
|
|
|
```typescript
|
|
// hooks/useSpotify.ts
|
|
import { ref } from 'vue'
|
|
|
|
export function useSpotify() {
|
|
const player = ref<any>(null)
|
|
const isReady = ref(false)
|
|
|
|
const initializePlayer = (token: string) => {
|
|
// Utilisation du spotify-player.js
|
|
player.value = new window.Spotify.Player({
|
|
name: 'Binôme Player',
|
|
getOAuthToken: (cb: (token: string) => void) => {
|
|
cb(token)
|
|
}
|
|
})
|
|
}
|
|
|
|
return {
|
|
player,
|
|
isReady,
|
|
initializePlayer
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🚀 Déploiement
|
|
|
|
### Build de Production
|
|
|
|
```bash
|
|
# Génération des fichiers optimisés
|
|
pnpm build
|
|
|
|
# Vérification de la build
|
|
pnpm preview
|
|
```
|
|
|
|
### Netlify (Configuration dans [`netlify.toml`](netlify.toml:1))
|
|
|
|
```toml
|
|
[build]
|
|
command = "pnpm build"
|
|
publish = "dist"
|
|
|
|
[[redirects]]
|
|
from = "/*"
|
|
to = "/index.html"
|
|
status = 200
|
|
```
|
|
|
|
### Variables d'Environnement
|
|
|
|
```bash
|
|
# .env.local (non versionné)
|
|
VITE_SPOTIFY_CLIENT_ID=your_client_id
|
|
VITE_API_BASE_URL=https://api.example.com
|
|
```
|
|
|
|
---
|
|
|
|
## 🐛 Debugging et Outils
|
|
|
|
### Vue DevTools
|
|
|
|
- Extension navigateur pour Vue 3
|
|
- Inspection des composants et du store Pinia
|
|
- Timeline des événements
|
|
|
|
### Vite DevTools
|
|
|
|
- HMR (Hot Module Replacement)
|
|
- Source maps automatiques
|
|
- Inspection des modules
|
|
|
|
### Console de Debug
|
|
|
|
```typescript
|
|
// Activation du debug en développement
|
|
if (import.meta.env.DEV) {
|
|
console.log('Mode développement activé')
|
|
// Exposition du store pour debug
|
|
window.__PINIA__ = pinia
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 📚 Ressources et Documentation
|
|
|
|
### Documentation Officielle
|
|
|
|
- [Vue 3](https://vuejs.org/)
|
|
- [Vite](https://vitejs.dev/)
|
|
- [Pinia](https://pinia.vuejs.org/)
|
|
- [Vue Router](https://router.vuejs.org/)
|
|
|
|
### Outils Recommandés
|
|
|
|
- **IDE** : VS Code avec extensions Vue
|
|
- **Extensions** : Vetur, TypeScript Vue Plugin
|
|
- **Browser** : Chrome/Firefox avec Vue DevTools
|
|
|
|
---
|
|
|
|
## 🔄 Workflow de Développement
|
|
|
|
### 1. Démarrage d'une Nouvelle Fonctionnalité
|
|
|
|
```bash
|
|
# Créer une branche
|
|
git checkout -b feature/nouvelle-fonctionnalite
|
|
|
|
# Démarrer le serveur de dev
|
|
pnpm dev
|
|
```
|
|
|
|
### 2. Développement
|
|
|
|
- Modifier les fichiers dans `src/`
|
|
- Tester en temps réel avec HMR
|
|
- Utiliser Vue DevTools pour debug
|
|
|
|
### 3. Tests et Validation
|
|
|
|
```bash
|
|
# Vérification du code
|
|
pnpm lint
|
|
|
|
# Build de test
|
|
pnpm build && pnpm preview
|
|
```
|
|
|
|
### 4. Commit et Push
|
|
|
|
```bash
|
|
# Commit avec message descriptif
|
|
git add .
|
|
git commit -m "feat: ajout de la nouvelle fonctionnalité"
|
|
git push origin feature/nouvelle-fonctionnalite
|
|
```
|
|
|
|
---
|
|
|
|
**Guide créé le 20 juillet 2025**
|
|
**Version de l'application** : Stack moderne Vue 3 + Vite + Pinia
|
|
**Prochaine mise à jour** : Après résolution des problèmes techniques identifiés
|