Cours Next.js · Module 1: Configuration de Next.js
Le rendu dans Next.js - vue d'ensemble des stratégies
Dans cette leçon8
À Quantum Metropolis, l'information parvient aux habitants de différentes manières - des écrans holographiques dans les rues affichent du contenu en temps réel, des panneaux d'information génèrent du contenu à l'avance, et des terminaux personnels récupèrent des données à la demande. De même, Next.js propose plusieurs stratégies de rendu des pages, chacune ayant son propre cas d'usage.
Dans ce chapitre, tu découvriras les quatre principales stratégies de rendu de Next.js. Nous n'entrerons pas dans les détails techniques approfondis - c'est un sujet pour le module 5. Pour l'instant, nous voulons que tu comprennes que ces stratégies existent et que tu saches quand chacune d'elles a du sens.
Qu'est-ce que le rendu ?
Le rendu est le processus de conversion du code React (JSX) en HTML que le navigateur peut afficher à l'utilisateur. La question clé est : où et quand ce processus a-t-il lieu ?
1// This React component...
2export default function Hello() {
3 return <h1>Welcome to Quantum Metropolis!</h1>;
4}
5
6// ...gets converted to HTML:
7// <h1>Welcome to Quantum Metropolis!</h1>Selon la stratégie choisie, cette conversion peut se produire :
- Sur le serveur - avant que la page n'atteigne le navigateur
- Dans le navigateur - après le téléchargement du code JavaScript
- Pendant le build - avant même que le serveur ne soit démarré
SSR - Server-Side Rendering (rendu côté serveur)
Imagine qu'à Quantum Metropolis, un écran holographique génère une image dans le centre de contrôle et transmet l'hologramme fini pour l'affichage. L'utilisateur voit une image complète immédiatement après avoir ouvert la transmission.
Le SSR signifie que le serveur rend la page HTML à chaque requête de l'utilisateur. Quand quelqu'un visite une page, le serveur :
- Récupère les données nécessaires (depuis une base de données, une API)
- Génère du HTML complet
- Envoie la page finie au navigateur
1// Server Component in Next.js - rendered on the server by default
2export default async function DashboardPage() {
3 // Data fetched with EVERY request
4 const stats = await fetch('https://api.quantum.com/stats', { cache: 'no-store' });
5 const data = await stats.json();
6
7 return (
8 <div>
9 <h1>Quantum Panel</h1>
10 <p>Active users: {data.activeUsers}</p>
11 <p>Last update: {data.timestamp}</p>
12 </div>
13 );
14}L'option cache: 'no-store' est indispensable ici : sans elle (et sans API liées à la requête comme cookies()), Next.js rend la page une seule fois, pendant next build.
Quand utiliser le SSR ?
- Quand les données changent souvent (par ex. tableau de bord utilisateur, panier)
- Quand le contenu doit être à jour à chaque rafraîchissement
- Quand tu as besoin de SEO pour du contenu dynamique
SSG - Static Site Generation (génération de site statique)
À Quantum Metropolis, les panneaux d'information avec les horaires sont imprimés une fois par jour et affichés aux arrêts. Ils ne changent pas à chaque seconde - ils sont préparés à l'avance.
Le SSG signifie que les pages HTML sont générées pendant le build de l'application (next build), et non à chaque requête. Les pages prêtes sont servies instantanément depuis un CDN.
1// Page generated statically during build
2export default function AboutPage() {
3 return (
4 <div>
5 <h1>About Quantum Metropolis</h1>
6 <p>Founded in 2150 as a center for future technologies.</p>
7 <p>Population: 12 million residents.</p>
8 </div>
9 );
10}
11// This page doesn't need dynamic data
12// Next.js will generate it once during 'next build'Quand utiliser le SSG ?
- Blog, documentation, page « À propos »
- Contenu qui change rarement
- Quand la vitesse de chargement maximale est la priorité
CSR - Client-Side Rendering (rendu côté client)
Les terminaux personnels des habitants de Quantum Metropolis téléchargent des données brutes et rendent l'interface localement - chaque terminal crée sa propre image sur son écran.
Le CSR signifie que les données (et, dans une SPA classique, toute l'interface) sont récupérées et rendues dans le navigateur. Dans Next.js, même un composant avec "use client" est pré-rendu en HTML sur le serveur à la première visite, puis hydraté : dans l'exemple ci-dessous, le serveur envoie le titre du chat et le navigateur récupère les messages.
1"use client";
2
3import { useState, useEffect } from 'react';
4
5export default function LiveChat() {
6 const [messages, setMessages] = useState([]);
7
8 useEffect(() => {
9 // Data fetched in the browser after component loads
10 fetch('/api/messages')
11 .then(res => res.json())
12 .then(data => setMessages(data));
13 }, []);
14
15 return (
16 <div>
17 <h2>Quantum Chat</h2>
18 {messages.map(msg => (
19 <p key={msg.id}>{msg.text}</p>
20 ))}
21 </div>
22 );
23}Quand utiliser le CSR ?
- Éléments interactifs (chat, formulaires, tableaux de bord en temps réel)
- Quand le SEO n'est pas nécessaire pour une section donnée
- Quand le composant nécessite l'accès aux API du navigateur (localStorage, géolocalisation)
ISR - Incremental Static Regeneration (régénération statique incrémentale)
À Quantum Metropolis, les panneaux d'information ont un mode de mise à jour automatique - ils sont statiques, mais à un intervalle défini (par ex. toutes les heures) le système vérifie s'il y a de nouvelles données et génère une version mise à jour.
L'ISR combine les avantages du SSG (vitesse) et du SSR (fraîcheur). La page est générée statiquement et, une fois le délai écoulé, la première requête déclenche sa régénération en arrière-plan (cette requête reçoit encore la version précédente).
1// Page with ISR - static, regenerated in the background at most once every 60 seconds
2export default async function ProductsPage() {
3 const res = await fetch('https://api.quantum.com/products', {
4 next: { revalidate: 60 } // Background regeneration at most once every 60 seconds
5 });
6 const products = await res.json();
7
8 return (
9 <div>
10 <h1>Quantum Store Products</h1>
11 {products.map(p => (
12 <div key={p.id}>
13 <h3>{p.name}</h3>
14 <p>{p.price} credits</p>
15 </div>
16 ))}
17 </div>
18 );
19}Quand utiliser l'ISR ?
- Boutique en ligne (les produits changent, mais pas à chaque seconde)
- Page d'articles/actualités
- Quand tu veux la vitesse du SSG mais avec des mises à jour
Schéma mental simple - quelle stratégie choisir ?
Voici un schéma de décision simple pour t'aider à choisir la bonne stratégie :
1Does the content change with every request?
2 YES -> Do you need SEO?
3 YES -> SSR (server rendering)
4 NO -> CSR (browser rendering)
5 NO -> Does the content change from time to time?
6 YES -> ISR (static with regeneration)
7 NO -> SSG (fully static)| Stratégie | Vitesse | Fraîcheur des données | SEO | Exemple d'usage |
|---|---|---|---|---|
| SSG | La plus rapide | Données du moment du build | Oui | Blog, documentation |
| ISR | Très rapide | Rafraîchies au plus toutes les X secondes | Oui | Boutique, actualités |
| SSR | Rapide | Toujours à jour | Oui | Tableau de bord, profil |
| CSR | Dépend du client | Récupérées en direct | Non | Chat, formulaires |
Et ensuite ?
Dans le module 5 de ce cours, nous plongerons dans les détails techniques de chaque stratégie de rendu. Tu apprendras :
- Comment configurer précisément le SSR et l'ISR dans l'App Router
- Comment optimiser les performances de rendu
- Comment combiner différentes stratégies dans une seule application
- Des patterns avancés avec les React Server Components
Pour l'instant, le plus important est de retenir que Next.js te laisse le choix - tu n'as pas à tout rendre de la même façon. Chaque page, et même chaque composant, peut utiliser une stratégie différente.
Résumé
Quantum Metropolis nous montre que différents systèmes de diffusion de l'information ont des applications différentes. De même dans Next.js :
- SSR - le serveur rend la page à chaque requête (données toujours à jour)
- SSG - page générée une seule fois pendant le build (le plus rapide)
- CSR - le navigateur rend la page après avoir téléchargé le JS (interactivité)
- ISR - page statique avec régénération automatique (compromis entre vitesse et fraîcheur)
Comprendre ces stratégies est le fondement du travail avec Next.js. Dans les modules suivants, tu les appliqueras en pratique, en construisant des applications de plus en plus avancées à Quantum Metropolis.
Code de cette leçon : App.tsx
1import React, { useState } from 'react';
2
3// Aperçu interactif des stratégies de rendu de Next.js
4const RenderingOverview = () => {
5 const [selected, setSelected] = useState<string | null>(null);
6
7 const strategies = [
8 {
9 id: 'ssr',
10 name: 'SSR',
11 fullName: 'Server-Side Rendering',
12 icon: '',
13 color: '#7c4dff',
14 speed: 'Rapide',
15 freshness: 'Toujours à jour',
16 seo: true,
17 description: 'Le serveur rend la page à CHAQUE requête. Les données sont toujours fraîches.',
18 useCase: 'Tableau de bord, profil utilisateur, panier',
19 code: 'export default async function Page() {\n const data = await fetch(url);\n return <div>{data.title}</div>;\n}',
20 },
21 {
22 id: 'ssg',
23 name: 'SSG',
24 fullName: 'Static Site Generation',
25 icon: '',
26 color: '#4caf50',
27 speed: 'La plus rapide',
28 freshness: 'Du moment du build',
29 seo: true,
30 description: 'Pages générées UNE SEULE fois pendant le build. Servies depuis un CDN.',
31 useCase: 'Blog, documentation, page À propos',
32 code: 'export default function About() {\n return <div>Static content</div>;\n}',
33 },
34 {
35 id: 'csr',
36 name: 'CSR',
37 fullName: 'Client-Side Rendering',
38 icon: '',
39 color: '#ff9800',
40 speed: 'Dépend du client',
41 freshness: 'Récupérées en direct',
42 seo: false,
43 description: 'Le navigateur télécharge le JS et rend la page lui-même.',
44 useCase: 'Chat, formulaires, tableaux de bord interactifs',
45 code: '"use client";\nimport { useState } from "react";\n// Rendu dans le navigateur',
46 },
47 {
48 id: 'isr',
49 name: 'ISR',
50 fullName: 'Incremental Static Regeneration',
51 icon: '',
52 color: '#e91e63',
53 speed: 'Très rapide',
54 freshness: 'Toutes les X secondes',
55 seo: true,
56 description: 'Page statique avec régénération automatique à intervalles définis.',
57 useCase: 'Boutique, articles, actualités',
58 code: 'const res = await fetch(url, {\n next: { revalidate: 60 }\n});',
59 },
60 ];
61
62 const active = strategies.find(s => s.id === selected);
63
64 return (
65 <div style={{ background: '#0f0f23', minHeight: '100vh', padding: '20px', color: '#fff', fontFamily: 'sans-serif' }}>
66 <h1 style={{ color: '#64ffda', textAlign: 'center', marginBottom: '8px' }}>
67 Stratégies de rendu de Next.js
68 </h1>
69 <p style={{ textAlign: 'center', color: '#888', marginBottom: '24px' }}>
70 Clique sur une stratégie pour voir les détails
71 </p>
72
73 <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: '12px', maxWidth: '800px', margin: '0 auto 24px' }}>
74 {strategies.map(s => (
75 <button key={s.id} onClick={() => setSelected(s.id)}
76 style={{ padding: '16px', background: selected === s.id ? s.color : 'rgba(255,255,255,0.05)',
77 border: selected === s.id ? 'none' : '1px solid #333', borderRadius: '10px',
78 color: '#fff', cursor: 'pointer', textAlign: 'center', transition: 'all 0.2s' }}>
79 <div style={{ fontSize: '2rem' }}>{s.icon}</div>
80 <div style={{ fontWeight: 'bold', marginTop: '4px' }}>{s.name}</div>
81 <div style={{ fontSize: '0.7rem', color: selected === s.id ? '#fff' : '#888' }}>{s.fullName}</div>
82 </button>
83 ))}
84 </div>
85
86 {active && (
87 <div style={{ maxWidth: '800px', margin: '0 auto', background: 'rgba(255,255,255,0.05)',
88 borderRadius: '12px', padding: '24px', border: '1px solid ' + active.color }}>
89 <h2 style={{ color: active.color, marginBottom: '12px' }}>{active.icon} {active.fullName}</h2>
90 <p style={{ color: '#b0bec5', marginBottom: '16px' }}>{active.description}</p>
91
92 <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: '12px', marginBottom: '16px' }}>
93 <div style={{ background: 'rgba(0,0,0,0.3)', padding: '12px', borderRadius: '8px', textAlign: 'center' }}>
94 <div style={{ color: '#888', fontSize: '0.8rem' }}>Vitesse</div>
95 <div style={{ color: '#64ffda', fontWeight: 'bold' }}>{active.speed}</div>
96 </div>
97 <div style={{ background: 'rgba(0,0,0,0.3)', padding: '12px', borderRadius: '8px', textAlign: 'center' }}>
98 <div style={{ color: '#888', fontSize: '0.8rem' }}>Fraîcheur</div>
99 <div style={{ color: '#64ffda', fontWeight: 'bold' }}>{active.freshness}</div>
100 </div>
101 <div style={{ background: 'rgba(0,0,0,0.3)', padding: '12px', borderRadius: '8px', textAlign: 'center' }}>
102 <div style={{ color: '#888', fontSize: '0.8rem' }}>SEO</div>
103 <div style={{ color: active.seo ? '#4caf50' : '#f44336', fontWeight: 'bold' }}>{active.seo ? 'Oui' : 'Non'}</div>
104 </div>
105 </div>
106
107 <div style={{ background: '#0d1117', padding: '12px', borderRadius: '8px', marginBottom: '12px' }}>
108 <pre style={{ color: '#64ffda', margin: 0, fontSize: '13px', whiteSpace: 'pre-wrap' }}>{active.code}</pre>
109 </div>
110
111 <p style={{ color: '#888', fontSize: '0.9rem' }}>
112 <strong style={{ color: '#7c4dff' }}>À utiliser quand :</strong> {active.useCase}
113 </p>
114 </div>
115 )}
116
117 {!active && (
118 <div style={{ textAlign: 'center', color: '#555', paddingTop: '40px' }}>
119 Sélectionne une stratégie de rendu ci-dessus
120 </div>
121 )}
122 </div>
123 );
124};
125
126export default RenderingOverview;Tu as repéré une erreur dans cette leçon ?
Teste tes connaissances
Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.
1. Quelle stratégie de rendu génère les pages HTML pendant le build de l'application (next build) ?
2. Qu'est-ce qui caractérise l'ISR (Incremental Static Regeneration) dans Next.js ?
3. Comment définir des variables d'environnement accessibles côté client dans Next.js ?
4. Que signifie la directive 'use client' placée au début d'un fichier dans Next.js ?
5. Quel outil ne fait PAS partie d'un environnement de développement Next.js typique ?
6. Quel dossier, dans Next.js (App Router), contient les définitions de pages et les routes ?
7. Quelle fonctionnalité de Next.js découpe automatiquement le code JavaScript en petits bundles chargés à la demande ?
Tâches pratiques dans le jeu
- Clique dans l'ordre
Ordonne le chemin correct vers le fichier layout dans l'App Router
- Tri vertical
Ordonne le cycle de vie du composant dans l'App Router
- Tri vertical
Ordonne la syntaxe d'utilisation du composant Image de Next.js
- Tri vertical
Ordonne le pipeline d'optimisation des images dans Next.js
- Clique dans l'ordre
Ordonne la structure JSX correcte avec un élément div et un titre h1
- Tri vertical
Ordonne la syntaxe de la fonction getStaticProps dans le Pages Router (dossier pages/)
- Tri vertical
Ordonne le traitement des requêtes HTTP dans Next.js
- Tri vertical
Ordonne la syntaxe de la fonction getServerSideProps dans le Pages Router (dossier pages/)
- Tri vertical
Ordonne le flux d'une requête API à travers le proxy (anciennement middleware)
- Éditeur de code
Construis avec l'App Router la page d'accueil d'un portfolio (fichier app/page.jsx) sous la forme d'un composant Portfolio exporté par défaut. Suis ces étapes dans l'ordre : 1. L'élément principal a className="portfolio". 2. En haut, place un <nav> avec trois liens <Link> de next/link : « Accueil » (/), « Projets » (/projects) et « Contact » (/contact). 3. Ajoute un titre <h1> avec ton prénom ou ton pseudo. 4. Crée un tableau projects avec au moins 2 objets { id, title } et affiche-le dans un <ul> avec map : chaque projet dans un <li key={project.id}> avec son titre. 5. Dans styles.css, ajoute une règle pour la classe .portfolio (par exemple un fond et des marges).