devsite/docs-site-interne/10-plan-server-components.md
2026-04-28 14:10:05 +02:00

117 lines
7.4 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 sexé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
<>
<PageHeader … /> // peut être serveur
<ListeClientOuMixte … /> // sous-arbre `"use client"` uniquement où nécessaire
</>
```
Les **carousels** (`Carousel`, `VignetteCarousel`) restent très probablement en **clients** tant quils 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`)
Aujourdhui: **`"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 1315 il faut vérifier quaucune 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.
Cest le point le plus **structurant** ; il sera arbitré au moment de limplé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**, sassurer que cette env pointe soit vers **`http://localhost:1337`**, soit vers lURL 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 denv par environnement** recommandée).
- Harmoniser avec **rewrites** existants **`/api/*` → Strapi**: possibilité dutiliser **`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 quavec `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)