7.4 — Méta-frameworks
🎯 Objectif : choisir lucidement entre rendu côté serveur, statique, hybride, edge — et utiliser Next.js (le plus répandu) en confiance.
À l'issue de cet axe, tu sauras :
- Distinguer CSR, SSR, SSG, ISR, edge rendering — et savoir quand chacun est pertinent
- Naviguer dans la structure App Router de Next.js
- Connaître Nuxt, SvelteKit, Remix et leurs équivalents
- Comprendre les server actions et la différence avec une API REST classique
- Choisir entre Vercel, Netlify, Render, Cloudflare pour héberger
Débutant
Pourquoi un méta-framework ?
Section intitulée « Pourquoi un méta-framework ? »Un framework pur (React, Vue) résout l’UI. Mais il te laisse choisir tout le reste : routing, SSR, data fetching, déploiement, optimisation des images, métadonnées, sitemap…
Un méta-framework intègre tout ça :
| Sous-jacent | Méta-framework |
|---|---|
| React | Next.js (Vercel) — dominant |
| React (alternative SPA-first) | TanStack Start (basé Vinxi + Vite, file-based routing typé) |
| Vue | Nuxt |
| Svelte | SvelteKit |
| React (focus loaders/actions) | Remix |
| Solid | SolidStart |
| Astro | (Astro est son propre méta-framework) |
Les 5 modes de rendu
Section intitulée « Les 5 modes de rendu »C’est le concept clé à maîtriser.
flowchart TD
CSR["CSR<br/>Client-Side Rendering<br/>HTML vide → JS dans le navigateur génère tout"]
SSR["SSR<br/>Server-Side Rendering<br/>HTML généré au serveur À CHAQUE requête"]
SSG["SSG<br/>Static Site Generation<br/>HTML généré au BUILD, servi tel quel"]
ISR["ISR<br/>Incremental Static Regeneration<br/>SSG + revalidation périodique"]
Edge["Edge rendering<br/>SSR mais sur un edge node proche de l'utilisateur"] CSR — Client-Side Rendering
Section intitulée « CSR — Client-Side Rendering »1. Navigateur reçoit un HTML vide + un gros bundle JS2. JS s'exécute, fetch les données, génère le DOM3. L'utilisateur voit quelque chose✅ Simple à mettre en place. ❌ Mauvais SEO (Google voit du vide initial). ❌ Lent au premier affichage (LCP).
C’est ce que fait une SPA pure (Create React App, Vite + React).
SSR — Server-Side Rendering
Section intitulée « SSR — Server-Side Rendering »1. Requête → serveur génère le HTML complet → renvoyé au client2. Le client affiche le HTML immédiatement3. JS s'hydrate ensuite pour rendre interactif✅ SEO parfait. ✅ LCP rapide. ❌ Charge serveur à chaque requête. ❌ Latence de génération.
SSG — Static Site Generation
Section intitulée « SSG — Static Site Generation »1. Au BUILD : on pré-génère toutes les pages en HTML2. À la requête : on sert le fichier statique depuis un CDN✅ Plus rapide possible (CDN). ✅ Coût d’hébergement minimal. ❌ Données figées au build → pas adapté à du contenu très dynamique.
Idéal pour : blogs, marketing, docs (ce site est en SSG).
ISR — Incremental Static Regeneration
Section intitulée « ISR — Incremental Static Regeneration »1. Comme SSG, mais avec revalidation périodique (ex. toutes les 60 s)2. La 1re requête après expiration déclenche la regenexport const revalidate = 60; // regénère après 60 s✅ Compromis SSG + données fraîches. ✅ Tient des milliers de pages.
Edge rendering
Section intitulée « Edge rendering »SSR exécuté sur un edge node (Cloudflare Workers, Vercel Edge Functions) proche de l’utilisateur.
✅ Latence très faible (~10 ms vs 100+ ms pour un serveur centralisé). ✅ Auto-scale mondial. ❌ Limites techniques (pas tous les modules Node, taille du bundle, durée d’exécution).
| Type de page | Mode idéal |
|---|---|
| Blog statique | SSG |
| Marketing | SSG |
| Liste produits e-commerce | ISR ou SSR |
| Dashboard admin perso | SSR |
| Page de profil utilisateur | SSR ou Edge |
| App temps réel (chat) | CSR ou hybride |
Next.js — App Router
Section intitulée « Next.js — App Router »Depuis Next 13+, l’App Router (dossier app/) remplace le Pages Router (dossier pages/). Tout ce qui suit est en App Router.
Next.js 16 — ce qui change en 2026
Section intitulée « Next.js 16 — ce qui change en 2026 »- Turbopack devient le bundler par défaut (Webpack n’est plus l’option principale).
- L’accès synchrone à
paramsest totalement supprimé : tu dois faireparams: Promise<{ id: string }>puisawait params. C’était deprecated en 15, c’est obligatoire en 16. - L’accès synchrone à
cookies()etheaders()est aussi supprimé :await cookies(),await headers(). - Améliorations de streaming SSR et de caching granulaire.
Ces changements concernent toutes les pages dynamiques. Si tu migres une app Next 14, fais-le par lots : un dossier de routes à la fois.
Structure
Section intitulée « Structure »app/├── layout.tsx ← layout racine (head, body, providers)├── page.tsx ← /├── about/│ └── page.tsx ← /about├── blog/│ ├── layout.tsx ← layout blog│ ├── page.tsx ← /blog│ └── [slug]/│ └── page.tsx ← /blog/:slug├── (marketing)/ ← grouping (n'apparaît PAS dans l'URL)│ ├── pricing/│ └── features/└── api/ └── users/ └── route.ts ← API endpoint /api/usersLayout racine
Section intitulée « Layout racine »export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="fr"> <body> <Header /> <main>{children}</main> <Footer /> </body> </html> );}Les layouts s’imbriquent — app/blog/layout.tsx enveloppe les pages de blog, à l’intérieur du layout racine.
export default async function ProductPage({ params }: { params: Promise<{ id: string }> }) { const { id } = await params; const product = await db.product.findUnique({ where: { id } }); if (!product) notFound(); return <h1>{product.name}</h1>;}Mode de rendu — par page
Section intitulée « Mode de rendu — par page »export const dynamic = 'force-dynamic'; // SSRexport const dynamic = 'force-static'; // SSGexport const revalidate = 60; // ISR avec 60 sPar défaut, Next 14+ détecte automatiquement (si tu utilises des cookies ou des params dynamiques → SSR ; sinon → SSG).
Loading et error states
Section intitulée « Loading et error states »// app/products/loading.tsx — pendant le chargement de la pageexport default function Loading() { return <Spinner />;}
// app/products/error.tsx — si une erreur survient'use client';export default function Error({ error, reset }: { error: Error; reset: () => void }) { return ( <div> <p>Erreur : {error.message}</p> <button onClick={reset}>Réessayer</button> </div> );}Métadonnées
Section intitulée « Métadonnées »// statiqueexport const metadata = { title: 'Mon site', description: 'Description de la page', openGraph: { images: ['/og.png'] },};
// dynamiqueexport async function generateMetadata({ params }) { const post = await db.post.findUnique({ where: { id: params.id } }); return { title: post.title };}API Routes (Route Handlers)
Section intitulée « API Routes (Route Handlers) »import { NextResponse } from 'next/server';
export async function GET() { const users = await db.user.findMany(); return NextResponse.json(users);}
export async function POST(request: Request) { const data = await request.json(); const user = await db.user.create({ data }); return NextResponse.json(user, { status: 201 });}Middleware — exécuté avant chaque requête
Section intitulée « Middleware — exécuté avant chaque requête »// middleware.ts (à la racine)import { NextResponse } from 'next/server';import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) { // Protéger /admin if (request.nextUrl.pathname.startsWith('/admin')) { const session = request.cookies.get('session'); if (!session) { return NextResponse.redirect(new URL('/login', request.url)); } } return NextResponse.next();}
export const config = { matcher: ['/admin/:path*', '/api/admin/:path*'],};Server Actions — au-delà de l’API REST
Section intitulée « Server Actions — au-delà de l’API REST »Au lieu d’écrire un endpoint POST + un client fetch, tu peux exposer une fonction serveur appelable directement depuis le client :
'use server';
async function sendFeedback(formData: FormData) { 'use server'; const message = formData.get('message') as string; await db.feedback.create({ data: { message } });}
export default function Page() { return ( <form action={sendFeedback}> <textarea name="message" required /> <button type="submit">Envoyer</button> </form> );}✅ Pas d’endpoint à écrire, pas de client fetch. ✅ Marche sans JS (le formulaire est natif). ✅ Validation côté serveur native.
Attention sécurité : une server action est appelable depuis n’importe où. Toujours valider et autoriser dedans (Zod + check de session).
Nuxt — l’équivalent Vue
Section intitulée « Nuxt — l’équivalent Vue »nuxt-app/├── pages/ ← file-based routing│ ├── index.vue│ └── products/[id].vue├── components/├── composables/ ← équivalent hooks├── server/│ └── api/│ └── users.ts└── nuxt.config.tsConcepts identiques à Next.js mais en Vue. SSR, SSG, ISR via nitro (le moteur sous-jacent).
SvelteKit — l’équivalent Svelte
Section intitulée « SvelteKit — l’équivalent Svelte »src/routes/├── +layout.svelte├── +page.svelte ← /├── +page.server.ts ← load() côté serveur└── products/[id]/ ├── +page.svelte └── +page.server.tsConvention +page.svelte (UI) vs +page.server.ts (serveur). Très propre.
Remix — focus loaders/actions
Section intitulée « Remix — focus loaders/actions »Approche anti-tendance par rapport à RSC : pas de Server Components, mais des loader() et action() clairs côté serveur, du HTML envoyé directement, et une approche très progressive enhancement.
// app/routes/products.$id.tsxexport async function loader({ params }) { return await db.product.findUnique({ where: { id: params.id } });}
export default function Product() { const product = useLoaderData<typeof loader>(); return <h1>{product.name}</h1>;}
export async function action({ request }) { const form = await request.formData(); // ...}Très bien pour les apps qui doivent marcher sans JS. Maintenu par Shopify (ils ont absorbé Remix en 2022).
Auto-évaluation
Section intitulée « Auto-évaluation »Pour aller plus loin
Section intitulée « Pour aller plus loin »- Next.js Docs — nextjs.org/docs
- Nuxt Docs — nuxt.com
- SvelteKit Docs — kit.svelte.dev
- Remix Docs — remix.run/docs
- Patterns.dev — Rendering Patterns — vue d’ensemble exhaustive
Suite : 7.5 — Outils de build — ce qui se passe quand tu fais npm run build.