# Plan — migration vers Server Components (données Strapi)
**Dernière mise à jour :** 2026-04-28
**Statut :** document de planification — **aucun changement de code appliqué** dans ce lot ; mise en œuvre quand vous le déciderez.
**Prérequis lu :** vous restez en **`npm run dev`** (Turbopack) pour le moment ; ce document décrit aussi ce que donne **`next build` / `next start`** en complément.
---
## 1. Objectif
Réduire le pattern actuel : pages marquées **`"use client"`** qui appellent **`fetch()` dans `useEffect`** après hydration.
Vers : **`async`** page (ou composant serveur parent) qui appelle **`fetch`** **côté serveur Next**, avec mise en **`cache`/revalidation** possible, puis rendu HTML **déjà rempli** de contenu texte + balises images.
---
## 2. État actuel (référence doc + code)
| Page / zone | Fichier | Pattern actuel |
|-------------|---------|----------------|
| Accueil | `app/page.tsx` | `"use client"` + `useEffect` → `getHomepageData()` |
| Liste portfolio | `app/portfolio/page.jsx` | idem → `/api/projects` |
| Liste compétences | `app/competences/page.jsx` | idem → `/api/competences` |
| Compétence (vignettes réalisations) | `app/competences/[slug]/page.tsx` | idem, fetchs multiples |
Conséquences documentées dans [`09-performances-images.md`](./09-performances-images.md) §3.4 : premier paint sans données, pas de data cache Next sur ces flux, images découvertes tard.
---
## 3. Ce que « Server Components » implique (concrètement)
### 3.1 Principe
- Un **Server Component** est un composant **sans** `"use client"` qui peut être **`async`** et utiliser **`await fetch(...)`** directement dans le corps du composant.
- Le rendu s’exécute **sur le serveur Node** (processus Next), **une fois par requête** (sauf cache), pas dans le navigateur.
### 3.2 Ce qui reste **obligatoirement** en Client Components
Tout ce qui utilise des **hooks** React hors contexte « serveur » limité : **`useState`**, **`useEffect`**, **`useRef`** pour le menu mobile, événements clavier (**Escape**), **Swiper**, **portal** pour modales, **localStorage**, etc.
**Stratégie classique :** fichier page **sans** `"use client"` (serveur), qui **`await`** les données puis rend :
```txt
<>
// peut être serveur
// sous-arbre `"use client"` uniquement où nécessaire
>
```
Les **carousels** (`Carousel`, `VignetteCarousel`) restent très probablement en **clients** tant qu’ils dépendent de Swiper avec effets hydratés — on leur **passe en props** les URLs / textes déjà résolus côté serveur.
### 3.3 **Layout root** (`app/layout.tsx`)
Aujourd’hui : **`"use client"`** (+ menu burger, état drawer, etc.). **Option A :** garder le layout tel quel et ne migrer **que les pages feuilles** — Next autorise une page serveur même si le layout parent est client (limites : enfants peuvent être serveur sous certaines compositions ; selon Next 13–15 il faut vérifier qu’aucune contrainte n’« impose » tout client — en pratique souvent extraction **ServerLayout** léger OU **layouts par segment** `/portfolio/layout.tsx` serveur). **Option B (plus tard) :** scinder en **layout serveur** + **header/footer client** importés dynamiquement ou composants clients enfants.
C’est le point le plus **structurant** ; il sera arbitré au moment de l’implémentation (lot par lot).
### 3.4 Appels Strapi : URL
- **Côté serveur Next**, **`getApiUrl()`** sans `window` utilise **`NEXT_PUBLIC_API_URL`** (ou défaut prod). Pour le dev **sur la même machine**, s’assurer que cette env pointe soit vers **`http://localhost:1337`**, soit vers l’URL publique **si** IIS/Strapi le servent aussi — sinon risque que le SSR appelle **`https://api.fernand…`** depuis le serveur sans route réseau correcte (**variable d’env par environnement** recommandée).
- Harmoniser avec **rewrites** existants **`/api/*` → Strapi** : possibilité d’utiliser **`fetch(new URL('/api/...', request.url ?? base))`** en SSR si vous préférez passer par Next (même origin).
### 3.5 `fetch` et cache
- **`fetch(url, { next: { revalidate: 60 } })`** : ISR-like, données rafraîchies au plus toutes les **60** secondes selon docs Next 15 (`cache` par défaut a évolué — à relire [`next` doc](https://nextjs.org/docs/app/building-your-application/data-fetching/fetching) au moment du codage).
- Pour du **toujours frais en dev**, **`cache: 'no-store'`** peut rester le comportement désiré jusqu’à validation.
### 3.6 Mode **`dev`** (Turbopack)
- Les Server Components **fonctionnent** en `next dev` ; le **cache** `fetch` est **moins représentatif** de la prod qu’avec `next start`.
- Le **gain perçu** (HTML complet, moins de waterfall client) reste **visible** en dev sur le **réseau** / **Elements** (contenu dans le HTML source).
---
## 4. Gains réels attendus
| Dimension | Avant (client fetch) | Après (données en serveur) |
|-----------|----------------------|----------------------------|
| **Premier contenu** | Spinner / squelette jusqu’à fin de `fetch` + JSON parse côté client | Texte + structure + **images** (`next/image` avec `src` déjà dans le HTML) plus tôt |
| **Waterfall** | HTML minimal → chargement JS → `useEffect` → fetch → re-render | Un aller-retour serveur Strapi lors du SSR Next (possible parallélisation `Promise.all`) |
| **Cache Next** | Aucun data cache pour ces pages | Possibilité **revalidate** / tags plus tard |
| **SEO / réseaux lents** | Contenu peu présent sans exécuter JS | Contenu lisible avec HTML seul (**meilleur** pour indexation ; utile même si votre besoin SEO est modeste) |
| **Lighthouse LCP** | Portrait / hero souvent retardé par la chaîne client | Déjà dans le flux initial SSR (**souvent gain LCP** mesurable après stabilisation)
**Limite honnête :** **`next dev`** conserve un JS **volumeux** (Turbopack, pas minifié comme prod). Le gain **bundle** sera **maximum** après **`next build` + `next start`** (ou équivalent).
---
## 5. Ordre de migration proposé (par risque croissant)
1. **`/portfolio`** (liste seule — une liste, pattern clair).
2. **`/competences`** (liste identique).
3. **`/`** (home — `getHomepageData` + retry ; extraire logique fetch dans `lib/` serveur).
4. **`/competences/[slug]`** (deux modes : vignettes réalisations vs redirect vers container compétences — attention aux branches).
Ensuite : fiches détail **`ContentSection`** / **`fetchData`** peuvent suivre une feuille de route analogue (nombreuses pages déjà partiellement factorisées via `fetchData`).
À chaque étape : **tests manuels** des routes, erreurs réseau Strapi, **images** encore correctes (**`pickStrapiImage`** inchangé côté props).
---
## 6. Hors scope immédiat (rappels)
- **Ne pas** renommer tous les fichiers **`.jsx`→`.tsx`** en même temps sans besoin ; migrer fichier par fichier.
- **Ne pas** activer **`compress: true`** côté Next tant que derrière **ARR/IIS** le tunnel reste incompatible (voir [`09-performances-images.md`](./09-performances-images.md) §4.6).
- **Évaluation `next build`** : à planifier après stabilisation SSR en dev ou sur une branche.
---
## 7. Liens internes
- Audit perf images & IIS : [`09-performances-images.md`](./09-performances-images.md)
- Front Next synthèse : [`02-frontend-next.md`](./02-frontend-next.md)
- Feuille de route : [`feuille-de-route.md`](./feuille-de-route.md)
- État actuel stack : [`etat-actuel.md`](./etat-actuel.md)