EN · English

Un cours pratique pour développeurs front-end débutants

Next.js de zéro jusqu'à votre premier site statique

Vous connaissez un peu de HTML, de CSS et de JavaScript. Vous avez 14 jours. Les 6 premiers, vous apprenez Next.js avec ce cours. Le reste du temps, vous construisez et livrez le site web d'une vraie entreprise, que votre formateur vous confiera.

6 jours pour apprendre 12 exercices pratiques 1 vrai site d'entreprise à livrer Aucune connaissance de React requise

L'idée la plus importante de tout ce cours

app/page.jsdevientmonsite.com/
app/about/page.jsdevientmonsite.com/about
app/menu/page.jsdevientmonsite.com/menu

Dans Next.js, les dossiers sont vos URLs. Si vous comprenez cette phrase, tout le reste du cours n'est que du détail.

Vert = fichiers & côté serveur Bleu = URLs dans le navigateur Ambre = interactif (côté client)
Sommaire du cours

Comment utiliser ce cours

  • Tapez chaque exemple de code vous-même. Pas de copier-coller. C'est en tapant que la syntaxe entre dans les doigts.
  • Faites chaque exercice avant d'ouvrir la solution. Être bloqué 10 minutes apprend plus qu'une heure de lecture.
  • Les cases à cocher se sauvegardent automatiquement dans votre navigateur : vous pouvez fermer cette page et reprendre plus tard.
  • Suivez le planning ci-dessous. Un jour à la fois. Si vous êtes en retard d'un jour, ce n'est pas grave ; si vous êtes en retard de trois, dites-le à votre formateur.
  • Bloqué plus de 15 minutes ? Chaque chapitre se termine par un bouton vert WhatsApp : il ouvre une conversation avec votre formateur, avec le chapitre déjà indiqué. Ajoutez votre question et envoyez.

Votre planning · 14 jours au total

JoursÀ faireVous savez que c'est bon quand...
1Chapitres 01 + 02 : comprendre Next.js, installer les outilsnode --version affiche un numéro
2Chapitre 03 : React (prenez la journée entière, c'est la base de tout)L'exercice 01 est fait sans regarder la solution
3Chapitres 04 + 05 + 06 : créer le projet, les pages, la navigationVotre site d'entraînement a 4 pages reliées entre elles
4Chapitres 07 + 08 : layouts et styleNav et footer partout, écrits une seule fois, et ça ressemble à un vrai site
5Chapitres 09 + 10 : images et "use client"Les FAQ s'ouvrent et se ferment
6Chapitres 11 + 12 + 13 : données, métadonnées, export statiquenpm run build passe sans erreur
7 à 12Chapitre 14 : LE VRAI PROJET, le site de l'entreprise confiée par votre formateur, un jalon par jourChaque jalon coché avant de passer au suivant
13Retours du formateur, corrections, finitionsLe build passe et le site est propre en largeur mobile
14Livraison et présentation du siteVous savez expliquer chaque fichier du projet

Le rythme est soutenu, c'est voulu : le cours ne contient que ce dont vous aurez besoin pour le vrai projet. Rien de ce que vous lisez ici n'est optionnel.

Partie 1 · Les bases

Chapitre 01

C'est quoi Next.js, et pourquoi ça existe ?

Objectif : savoir expliquer en une phrase ce qu'est Next.js et pourquoi une équipe le choisirait plutôt que des fichiers HTML classiques.

Partons de ce que vous connaissez

Imaginez que vous construisez un site à l'ancienne : un fichier HTML par page. index.html, about.html, contact.html. Ça marche. Mais trois problèmes apparaissent très vite :

  1. La répétition. Votre barre de navigation et votre pied de page sont copiés dans chaque fichier. Changez un lien du menu et vous devez modifier toutes les pages. Avec 30 pages, vous en oublierez une, et le site devient incohérent.
  2. Pas de composants. Vous avez une belle « carte » utilisée 20 fois. En HTML pur, ce sont 20 copies du même code. Impossible de dire « voici ma Carte, réutilise-la ».
  3. Les données, c'est pénible. Si vos articles de menu vivent dans une liste quelque part, le HTML ne sait pas boucler dessus. Vous écrivez chaque élément à la main.

React résout ces problèmes. React est une bibliothèque JavaScript qui permet de construire une page à partir de briques réutilisables appelées composants, et de générer du HTML à partir de données. Nous apprendrons juste ce qu'il faut de React au chapitre 3.

Et Next.js dans tout ça ?

React seul n'est qu'une bibliothèque. Il ne répond pas aux questions : comment fonctionnent les URLs ? Comment avoir plusieurs pages ? Comment rendre le site rapide ? Comment le mettre sur un vrai serveur ? Avant, chaque équipe répondait elle-même à ces questions, différemment, et souvent mal.

Next.js est un framework construit au-dessus de React qui répond à toutes ces questions pour vous. Il vous donne :

Vous avez besoin deNext.js vous donne
Plusieurs pages avec des URLs propresLe routing par fichiers : créez un dossier, obtenez une URL
Navigation et pied de page partagésLes layouts : écrits une fois, toutes les pages en héritent
Un développement confortablenpm run dev avec rechargement instantané à chaque sauvegarde
Des pages rapides pour les visiteursLes pages sont pré-construites en HTML avant toute visite
Images, polices, métadonnées optimiséesDes composants et une configuration intégrés
Un moyen de livrerUne commande produit un dossier hébergeable n'importe où

La définition en une phrase

Next.js est un framework qui prend des composants React et les transforme en un site web complet, rapide et multi-pages, en gérant pour vous le routing, les layouts et le build.

« Statique » veut dire pré-construit

Dans ce cours, nous construisons un site statique. Statique signifie : quand vous lancez la commande de build, Next.js génère des fichiers HTML, CSS et JavaScript finis. Le navigateur du visiteur ne fait que les télécharger. Pas de base de données, pas de code serveur exécuté à chaque visite. Résultat : un site extrêmement rapide, très peu cher à héberger et difficile à pirater. C'est parfait pour les portfolios, restaurants, agences, pages vitrines et documentations.

Vérifiez-vous : votre client a un site vitrine de 25 pages et se plaint que modifier le pied de page prend une heure. Quelle fonctionnalité de Next.js règle ça ?
Les layouts. Le pied de page est écrit une seule fois dans un fichier layout, et les 25 pages le partagent. Une modification met tout à jour. Nous construisons ça au chapitre 7.
Vérifiez-vous : Next.js remplace-t-il React ?
Non. Next.js est construit au-dessus de React. Vous écrivez des composants React ; Next.js les transforme en site complet avec pages, URLs et build. Quand vous écrivez du Next.js, vous écrivez toujours du React.

Chapitre 02

Installer les outils

Objectif : une installation Node.js qui fonctionne, un éditeur de code, et de l'aisance dans le terminal.

1. Node.js

Next.js tourne sur Node.js, qui permet d'exécuter du JavaScript sur votre ordinateur et pas seulement dans un navigateur. Téléchargez la version LTS (la version stable, actuellement 22.x) sur nodejs.org et installez-la avec les options par défaut.

Ensuite, ouvrez un terminal et vérifiez :

TerminalVous tapez ça
$ node --version
v22.11.0
$ npm --version
10.9.0

Si vous voyez des numéros de version (les vôtres peuvent différer légèrement), c'est bon. npm est venu automatiquement avec : c'est l'outil qui télécharge les paquets JavaScript, y compris Next.js lui-même.

2. Un éditeur de code

Prenez VS Code sur code.visualstudio.com sauf si vous avez déjà un favori. Extensions recommandées : ES7+ React snippets et Prettier (formate automatiquement le code à la sauvegarde, fini les débats sur l'indentation).

3. Kit de survie du terminal

Vous n'avez besoin que de cinq commandes pour tout ce cours :

CommandeCe qu'elle fait
cd mon-dossierEntrer dans un dossier (« change directory »)
cd ..Remonter d'un dossier
ls (Mac/Linux) ou dir (Windows)Lister le contenu du dossier courant
npm run devLancer le serveur de développement (vous la taperez tous les jours)
Ctrl + CArrêter ce qui tourne dans le terminal

L'erreur de débutant la plus fréquente

Lancer les commandes dans le mauvais dossier. Si npm run dev répond quelque chose comme « no such file package.json », vous n'êtes pas dans le dossier du projet. Faites d'abord cd mon-projet, puis réessayez.

Chapitre 03

React en 30 minutes

Objectif : comprendre les composants, le JSX, les props, le state et l'affichage de listes. C'est tout le React nécessaire pour ce cours.

Les composants : des fonctions qui retournent du HTML

Un composant React est simplement une fonction JavaScript dont le nom commence par une majuscule et qui retourne quelque chose qui ressemble à du HTML. Cette syntaxe retournée s'appelle le JSX.

Un composant minimalConcept
function Welcome() {
  return <h1>Bonjour l'équipe !</h1>;
}

Une fois le composant créé, vous l'utilisez comme une balise HTML personnalisée : <Welcome />. C'est le super-pouvoir que le HTML n'a jamais eu : inventer vos propres balises.

JSX : cinq règles qui couvrent 95 % des cas

  1. Retournez un seul élément racine. S'il en faut plusieurs, enveloppez-les dans une <div> ou dans un enveloppeur vide <> ... </> (appelé fragment).
  2. class devient className, car class est un mot réservé en JavaScript. De même, for devient htmlFor.
  3. Toute balise doit se fermer. <img> devient <img />, <br> devient <br />.
  4. Les accolades { } signifient « ici, du JavaScript ». Dedans, vous pouvez mettre une variable, un calcul ou un appel de fonction.
  5. Les commentaires dans le JSX s'écrivent {/* comme ça */}, pas <!-- comme ça -->.
Du JSX avec du JavaScript dedansConcept
function Greeting() {
  const name = "Sara";
  const hour = 14;
  return (
    <div className="greeting">
      {/* accolades = porte d'entrée vers le JavaScript */}
      <h1>Bonjour, {name} !</h1>
      <p>{hour < 12 ? "Bonne matinée" : "Bon après-midi"}</p>
    </div>
  );
}

Les props : passer des données à un composant

Un composant devient vraiment réutilisable quand on peut lui passer des données, comme les balises HTML acceptent des attributs. On appelle ça les props (« properties »). Le composant les reçoit dans un objet unique, qu'on déballe en général directement :

Les props rendent un composant réutilisableConcept
function ProfileCard({ name, job }) {
  return (
    <div className="card">
      <h2>{name}</h2>
      <p>{job}</p>
    </div>
  );
}

// Utilisé trois fois, avec des données différentes :
function Team() {
  return (
    <section>
      <ProfileCard name="Sara" job="Designer" />
      <ProfileCard name="Ali" job="Développeur" />
      <ProfileCard name="Lina" job="Cheffe de projet" />
    </section>
  );
}

Un seul design de carte, écrit une fois, rempli avec des données différentes. C'est la promesse « fini le copier-coller » du chapitre 1, tenue.

Afficher une liste avec .map()

Quand vos données vivent dans un tableau, vous transformez chaque élément en JSX avec la méthode .map(). Chaque élément généré doit avoir une prop key avec une valeur unique, pour que React puisse suivre les éléments.

Du tableau au HTMLConcept
const team = [
  { name: "Sara", job: "Designer" },
  { name: "Ali", job: "Développeur" },
  { name: "Lina", job: "Cheffe de projet" },
];

function Team() {
  return (
    <section>
      {team.map((person) => (
        <ProfileCard key={person.name} name={person.name} job={person.job} />
      ))}
    </section>
  );
}

Ajouter un membre de l'équipe, c'est désormais ajouter une ligne de données, pas copier un bloc de HTML. Relisez ce code lentement jusqu'à ce qu'il soit clair : c'est le motif que vous utiliserez le plus dans le travail réel.

Le state : des valeurs qui changent quand l'utilisateur interagit

Les props arrivent de l'extérieur et ne changent pas. Quand un composant a besoin de sa propre valeur changeante (un compteur, un menu ouvert/fermé, le texte d'un champ), il utilise le state via la fonction useState :

Le state avec useStateInteractif
"use client"; // obligatoire dans Next.js, expliqué au chapitre 10
import { useState } from "react";

function Counter() {
  const [count, setCount] = useState(0);
  return (
    <button onClick={() => setCount(count + 1)}>
      Cliqué {count} fois
    </button>
  );
}

Lisez-le ainsi : « donne-moi une valeur count qui démarre à 0, et une fonction setCount pour la changer ». Quand setCount s'exécute, React réaffiche le composant avec la nouvelle valeur. Vous ne touchez jamais le DOM vous-même : vous changez la donnée, React met l'écran à jour.

Démo en direct · ce bouton est réel, essayez-le
Exactement le composant Counter ci-dessus, qui tourne ici.
Exercice 01~25 min · papier ou bac à sable React en ligne

Penser en composants

Voir la solution
Solution
function MenuItem({ name, price }) {
  return (
    <li>
      {name} · {price} €
    </li>
  );
}

const items = [
  { name: "Espresso", price: 2.5 },
  { name: "Cappuccino", price: 3.5 },
  { name: "Croissant", price: 2.0 },
];

function Menu() {
  return (
    <ul>
      {items.map((item) => (
        <MenuItem key={item.name} name={item.name} price={item.price} />
      ))}
    </ul>
  );
}

Si votre version diffère un peu mais affiche trois éléments de liste, c'est correct.

Partie 2 · Le cœur de Next.js

Chapitre 04

Créer le projet, et visite guidée de chaque fichier

Objectif : un projet Next.js qui tourne sur votre machine, et vous savez à quoi sert chaque fichier.

Une commande crée tout

TerminalVous tapez ça
$ npx create-next-app@latest mon-premier-site

L'installateur pose quelques questions. La formulation exacte change selon les versions ; répondez avec ce tableau et vous serez aligné avec ce cours :

QuestionRéponsePourquoi
TypeScript ?NoOn apprend d'abord en JavaScript pur. TypeScript viendra plus tard dans votre carrière.
ESLint / linter ?YesIl vous signale les erreurs pendant que vous tapez.
Tailwind CSS ?NoOn apprend d'abord le vrai CSS pour comprendre ce que fait n'importe quel outil en dessous.
Dossier src/ ?NoMoins de dossiers à gérer mentalement.
App Router ?YesLa méthode moderne. Tout ce cours l'utilise.
Turbopack ?YesServeur de dev plus rapide. Acceptez le défaut.
Import alias ?NoGardez le défaut.

Puis lancez le serveur de développement :

TerminalVous tapez ça
$ cd mon-premier-site
$ npm run dev

  ▲ Next.js
  - Local:  http://localhost:3000

Ouvrez http://localhost:3000 dans votre navigateur. Vous devriez voir la page d'accueil de Next.js. localhost:3000 signifie « un site servi par mon propre ordinateur, sur le port 3000 ». Vous seul pouvez le voir. Laissez ce terminal tourner pendant que vous travaillez ; faites Ctrl + C pour l'arrêter.

Visite du projet

mon-premier-site/ · ce que l'installateur a créé
app/← votre site vit ici. 90 % de votre temps se passe dans ce dossier
page.jsla page d'accueil ( / )
layout.jsle cadre autour de chaque page
globals.cssles styles de tout le site
favicon.icola petite icône de l'onglet
public/images et fichiers servis tels quels (chapitre 9)
node_modules/les paquets téléchargés. Ne jamais modifier, ne jamais mettre dans git
package.jsonnom du projet, scripts, liste des dépendances
next.config.mjsréglages de Next.js (on le modifie une fois, au chapitre 13)
jsconfig.json, eslint.config.mjsconfig d'outillage. À ignorer pour l'instant

Deux fichiers comptent aujourd'hui. D'abord, app/page.js est votre page d'accueil. Une page n'est qu'un composant React exporté par défaut :

app/page.jsRemplacez son contenu
export default function Home() {
  return (
    <main>
      <h1>Mon premier site Next.js</h1>
      <p>Il est vivant !</p>
    </main>
  );
}

Sauvegardez le fichier et regardez le navigateur : il se met à jour instantanément, sans que vous rafraîchissiez. C'est le rechargement à chaud (hot reload), et c'est pour ça que le serveur de dev reste allumé.

Ensuite, app/layout.js est le cadre autour de chaque page. Remarquez qu'il affiche {children} ; c'est là que le contenu de chaque page apparaît. Nous le travaillerons sérieusement au chapitre 7.

Le rythme quotidien

Chaque session de travail à partir de maintenant, c'est : ouvrir le dossier du projet dans VS Code, ouvrir le terminal, lancer npm run dev, modifier des fichiers, regarder le navigateur se mettre à jour. C'est tout le workflow.

Exercice 02~20 min

Faites-en le vôtre

Chapitre 05

Pages et routing : les dossiers deviennent des URLs

Objectif : créer de nouvelles pages et prédire exactement quelle URL chaque fichier obtiendra.

La règle

Souvenez-vous du schéma en haut de ce cours. Voici la règle complète :

La règle du routing

Dans app/, chaque dossier devient un segment d'URL, et le fichier page.js du dossier est ce que les visiteurs voient à cette URL. Pas de page.js dans un dossier = pas de page à cette URL.

Donc pour créer une page « À propos » à l'adresse /about, vous créez un dossier app/about/ contenant un fichier page.js :

app/about/page.jsNouveau fichier
export default function AboutPage() {
  return (
    <main>
      <h1>À propos de nous</h1>
      <p>Nous sommes une petite équipe qui aime le web.</p>
    </main>
  );
}

Sauvegardez, puis visitez localhost:3000/about. C'est tout. Aucun fichier de configuration, aucun enregistrement de route. La structure des dossiers est la configuration.

Les dossiers s'imbriquent, et les URLs aussi : app/services/design/page.js est servi à /services/design.

Interactif · terrain de jeu du routing

Cliquez sur un fichier. Le faux navigateur montre l'URL qu'il créerait.

localhost:3000/
La page d'accueil.

Les noms de fichiers spéciaux dans app/

Next.js réserve quelques noms de fichiers. Chacun a un seul rôle :

FichierRôle
page.jsLe contenu d'une page. Obligatoire pour que l'URL existe.
layout.jsLe cadre partagé autour des pages (chapitre 7).
not-found.jsVotre page 404 personnalisée.

Il en existe d'autres (loading.js, error.js...), mais ces trois-là suffisent pour tout ce cours. Tout fichier portant un autre nom (comme hero.js ou data.js) est ignoré par le routeur : pas de risque de créer une URL par accident.

Exercice 03~20 min

Faites grandir le site à quatre pages

Voir la solution
Structure obtenue
app/
page.js/
about/page.js/about
contact/page.js/contact
services/
web/page.js/services/web

Chaque page.js est un petit composant exporté par défaut, comme l'exemple « À propos » ci-dessus.

Chapitre 06

Naviguer avec <Link>

Objectif : relier vos pages avec une navigation rapide, digne d'une application.

Vous pourriez relier les pages avec une balise <a href="/about"> classique, et ça marcherait. Mais un <a> brut force le navigateur à jeter toute la page et à retélécharger la suivante de zéro : écran blanc, lenteur.

Next.js fournit à la place un composant <Link>. Il ressemble à un lien et se comporte comme un lien (clic droit, ouvrir dans un nouvel onglet, suivi par les moteurs de recherche), mais Next.js remplace le contenu de la page sans rechargement complet, et pré-charge même les pages que le visiteur va probablement ouvrir. Même HTML en dessous, expérience bien plus rapide.

app/page.jsModifier
import Link from "next/link";

export default function Home() {
  return (
    <main>
      <h1>Mon premier site Next.js</h1>
      <p>
        En savoir plus <Link href="/about">sur nous</Link>.
      </p>
    </main>
  );
}

Lire la ligne d'import

import Link from "next/link" signifie : « apporte le composant Link du paquet Next.js dans ce fichier ». Tout composant ou fonction venant d'un autre fichier doit être importé en haut. Si vous oubliez, l'erreur dit « Link is not defined » : ce message est votre rappel.

La règle pratique : <Link> pour les pages internes à votre site, un <a> normal pour les sites externes (comme un lien vers Instagram).

Un composant de navigation

Une barre de navigation est le composant personnalisé idéal pour commencer. Créez un dossier components/ à la racine du projet (à côté de app/, pas dedans) pour ranger les briques réutilisables :

components/Nav.jsNouveau fichier
import Link from "next/link";

export default function Nav() {
  return (
    <nav>
      <Link href="/">Accueil</Link>
      <Link href="/about">À propos</Link>
      <Link href="/contact">Contact</Link>
    </nav>
  );
}

Et utilisez-le dans une page. Comme Nav.js est notre propre fichier (pas un paquet), le chemin d'import commence par des points qui décrivent où est le fichier par rapport au fichier courant :

app/page.jsModifier
import Nav from "../components/Nav";

export default function Home() {
  return (
    <main>
      <Nav />
      <h1>Mon premier site Next.js</h1>
    </main>
  );
}

../ signifie « remonte d'un dossier » : de app/ vers la racine du projet, puis dans components/. Se tromper de chemin d'import est l'erreur de débutant numéro un ; quand ça arrive, le message d'erreur nomme le chemin introuvable, alors vérifiez d'abord les points.

Mais attendez : faut-il maintenant importer <Nav /> dans chaque page ? Ce serait à nouveau le problème du copier-coller. Non. Le chapitre suivant le règle proprement.

Exercice 04~15 min

Branchez tout

Chapitre 07

Les layouts : construire le cadre une seule fois

Objectif : un en-tête et un pied de page partagés sur chaque page, écrits exactement une fois.

Ouvrez app/layout.js. Simplifié, il ressemble à ceci :

app/layout.jsLe layout racine
import "./globals.css";

export const metadata = {
  title: "Mon premier site",
  description: "Construit en apprenant Next.js",
};

export default function RootLayout({ children }) {
  return (
    <html lang="fr">
      <body>{children}</body>
    </html>
  );
}

Voici le modèle mental. Le layout est un cadre de tableau ; chaque page est le tableau. Quand quelqu'un visite /about, Next.js prend le layout et insère la page À propos exactement là où se trouve {children}. Visitez /contact, et le même cadre reçoit la page Contact à la place.

children est une prop que React remplit automatiquement avec ce qui est imbriqué à l'intérieur. Vous ne l'appelez jamais vous-même ; vous marquez seulement sa place.

Mettez la nav et le footer dans le cadre

app/layout.jsModifier
import "./globals.css";
import Nav from "../components/Nav";

export const metadata = {
  title: "Mon premier site",
  description: "Construit en apprenant Next.js",
};

export default function RootLayout({ children }) {
  return (
    <html lang="fr">
      <body>
        <Nav />
        {children}
        <footer>© 2026 Mon premier site</footer>
      </body>
    </html>
  );
}

Supprimez maintenant <Nav /> (et son import) de votre page d'accueil : sinon il apparaîtrait deux fois. Naviguez dans le site. Chaque page a la nav et le footer, et aucun fichier de page ne les mentionne. C'est la solution au problème du copier-coller du chapitre 1. La mise à jour du footer sur 25 pages qui prenait une heure est devenue une modification d'une ligne.

Un dernier fait à retenir : le layout racine est le seul endroit de toute l'application avec les balises <html> et <body>. Les pages ne les incluent jamais.

Vérifiez-vous : vous voulez ajouter une bannière « Fermé en août » visible sur toutes les pages. Dans quel fichier l'écrivez-vous ?
Dans app/layout.js, juste au-dessus de {children}. Une seule modification, toutes les pages l'affichent. Si vous avez pensé « dans chaque page », relisez ce chapitre.
Exercice 05~15 min

Un cadre pour tout

Chapitre 08

Le style : CSS global et CSS Modules

Objectif : savoir où vont les styles de tout le site, où vont les styles d'un composant, et pourquoi les deux sont séparés.

Le CSS global : les règles de tout le site

app/globals.css est déjà importé par votre layout racine, donc tout ce qu'il contient s'applique partout. C'est le bon endroit pour les fondations : polices, couleur de fond, couleur des liens, resets. Remplacez son contenu par quelque chose de petit et lisible :

app/globals.cssRemplacez le contenu
* {
  box-sizing: border-box;
}

body {
  margin: 0;
  font-family: system-ui, sans-serif;
  line-height: 1.6;
  color: #1f2933;
  background: #ffffff;
}

main {
  max-width: 720px;
  margin: 0 auto;
  padding: 24px;
}

Les CSS Modules : des styles qui ne peuvent pas fuir

Voici un accident d'équipe classique : vous écrivez .card { padding: 20px } pour le menu, et un mois plus tard un collègue nomme autre chose .card sur la page contact. Les styles entrent en collision et une page casse mystérieusement.

Les CSS Modules empêchent ça. Nommez un fichier Quelquechose.module.css et Next.js rend chaque classe privée au composant qui l'importe, en renommant les classes en coulisses en quelque chose d'unique comme Nav_card__x7Kd2. Deux fichiers peuvent utiliser .card sans jamais se gêner.

components/Nav.module.cssNouveau fichier
.nav {
  display: flex;
  gap: 24px;
  padding: 16px 24px;
  border-bottom: 1px solid #e2e8f0;
}

.nav a {
  text-decoration: none;
  color: #1f2933;
  font-weight: 600;
}

.nav a:hover {
  color: #0e7c5b;
}
components/Nav.jsModifier
import Link from "next/link";
import styles from "./Nav.module.css";

export default function Nav() {
  return (
    <nav className={styles.nav}>
      <Link href="/">Accueil</Link>
      <Link href="/about">À propos</Link>
      <Link href="/contact">Contact</Link>
    </nav>
  );
}

Lisez le motif : on importe la feuille de style comme un objet appelé styles, puis on écrit className={styles.nav}. Le nom de classe vient du JavaScript (d'où les accolades), et il correspond à la règle .nav du fichier module.

La règle d'équipe

CSS global pour les fondations qui s'appliquent partout (polices, couleurs, resets). Un CSS Module à côté de chaque composant pour son apparence propre. Dans le doute, choisissez le module : les styles qui fuient causent les bugs les plus déroutants dans les projets d'équipe.

Exercice 06~30 min

Donnez-lui un vrai look

Chapitre 09

Les images et le dossier public/

Objectif : ajouter des images au site de la bonne façon, celle de Next.js.

Le dossier public/

Tout ce que vous mettez dans public/ est servi depuis la racine de votre site, tel quel. Un fichier public/logo.png est accessible dans le navigateur à /logo.png. Notez que l'URL n'inclut pas le mot « public ».

public/ correspond à la racine du site
public/
logo.png→ monsite.com/logo.png
images/
team.jpg→ monsite.com/images/team.jpg

Le composant <Image>

Vous pourriez utiliser une balise <img> classique, mais Next.js fournit un composant <Image> amélioré qui charge les images paresseusement (elles ne se téléchargent qu'en arrivant à l'écran) et empêche la page de sauter pendant le chargement. Ce saut est un vrai problème de référencement et d'ergonomie appelé « layout shift », et c'est pourquoi width et height sont obligatoires : ils réservent l'espace à l'avance.

app/about/page.jsModifier
import Image from "next/image";

export default function AboutPage() {
  return (
    <main>
      <h1>À propos de nous</h1>
      <Image
        src="/images/team.jpg"
        alt="Notre équipe devant le bureau"
        width={720}
        height={480}
      />
    </main>
  );
}
  • src commence par / et c'est le chemin dans public/.
  • alt décrit l'image pour les visiteurs non-voyants et pour les moteurs de recherche. Écrivez-le comme si vous décriviez la photo au téléphone. Image purement décorative ? Utilisez alt="".
  • width et height sont des nombres entre accolades (des nombres JavaScript, pas des chaînes). Respectez les vraies proportions de l'image.

À retenir pour le chapitre 13

Sur un serveur classique, <Image> redimensionne et compresse aussi les images à la volée. Un export statique n'a pas de serveur, donc au chapitre 13 nous désactiverons cette seule fonctionnalité avec une ligne de configuration. Tout le reste de <Image> continue de fonctionner.

Exercice 07~15 min

Ajoutez de vraies images

Chapitre 10

Composants Server et Client

Objectif : savoir quand un fichier a besoin de "use client" en première ligne, et pourquoi la plupart n'en ont pas besoin.

Chaque composant du dossier app/ est, par défaut, un Server Component : Next.js le transforme en HTML fini à l'avance. Ce HTML est léger et instantané pour le visiteur. Toutes les pages que vous avez construites jusqu'ici sont des Server Components, et c'est exactement ce qu'il faut pour un site statique.

Mais certaines choses ne peuvent se passer que dans le navigateur du visiteur : réagir aux clics, mémoriser un état, lire la taille de la fenêtre. Un composant qui fait cela doit être un Client Component, et on le marque en écrivant une ligne tout en haut du fichier :

components/FaqItem.jsNouveau fichier · regardez la ligne 1
"use client";

import { useState } from "react";

export default function FaqItem({ question, answer }) {
  const [open, setOpen] = useState(false);
  return (
    <div>
      <button onClick={() => setOpen(!open)}>{question}</button>
      {open && <p>{answer}</p>}
    </div>
  );
}

Deux nouveautés dans ce code : setOpen(!open) bascule la valeur entre vrai et faux, et {open && <p>...</p>} signifie « n'affiche ce paragraphe que quand open est vrai ».

La décision est mécanique

Le composant...TypeMarqueur
affiche du texte, des images, des liens, des listes de donnéesServer (défaut)rien
utilise useState, useEffect, ou un onClick / onChangeClient"use client" en ligne 1
utilise des choses du navigateur comme window ou localStorageClient"use client" en ligne 1

En pratique, vous n'avez même pas à mémoriser ce tableau : si vous utilisez useState dans un fichier sans le marqueur, Next.js s'arrête avec une erreur qui vous dit littéralement d'ajouter "use client". Lisez les erreurs ; ce sont généralement des instructions.

Gardez l'ambre petit

Le bon style Next.js : garder les pages en Server Components et ne rendre « client » que la petite pièce interactive. La page À propos reste rendue côté serveur ; seul le petit FaqItem à l'intérieur porte "use client". Ne collez jamais "use client" en haut de chaque fichier « au cas où » : vous jetteriez la vitesse que Next.js vous offre gratuitement.

Et oui, les Client Components fonctionnent dans notre export statique. Leur HTML est pré-construit comme tout le reste, et leur JavaScript s'exécute dans le navigateur du visiteur pour les rendre interactifs.

Vérifiez-vous : un Footer qui affiche l'année, et un menu hamburger mobile qui s'ouvre au toucher. Lequel a besoin de "use client" ?
Seulement le menu hamburger : il réagit à un toucher et mémorise l'état ouvert/fermé, il lui faut donc useState et onClick. Le footer ne fait qu'afficher du contenu, il reste un Server Component sans marqueur.
Exercice 08~30 min

Votre premier composant interactif

Voir la solution du bonus
components/FaqItem.js
<button onClick={() => setOpen(!open)}>
  {open ? "-" : "+"} {question}
</button>

Le motif condition ? a : b choisit entre deux valeurs. C'est le même que dans l'exemple Greeting du chapitre 3.

Chapitre 11

Des données à l'interface

Objectif : garder le contenu dans un fichier de données et l'afficher avec des composants, comme sont construits les vrais sites.

Les vrais sites séparent le contenu de la présentation. Les prix du menu vivent dans un fichier de données ; les composants décident de leur apparence. Quand le client dit « le cappuccino passe à 4 euros », vous changez un nombre, pas du HTML.

Créez un dossier de données à la racine du projet :

data/menu.jsNouveau fichier
export const menuItems = [
  { id: 1, name: "Espresso", price: 2.5, desc: "Court et corsé." },
  { id: 2, name: "Cappuccino", price: 3.5, desc: "Le classique crémeux." },
  { id: 3, name: "Flat White", price: 3.8, desc: "Soyeux et doux." },
  { id: 4, name: "Croissant", price: 2.0, desc: "Cuit chaque matin." },
];

Notez que c'est un export nommé (pas de default). Un fichier peut avoir plusieurs exports nommés, et on les importe avec des accolades portant le nom exact.

Maintenant, un composant carte et une page qui combine tout ce que vous avez appris :

components/MenuCard.jsNouveau fichier
import styles from "./MenuCard.module.css";

export default function MenuCard({ name, price, desc }) {
  return (
    <article className={styles.card}>
      <div className={styles.top}>
        <h3>{name}</h3>
        <span className={styles.price}>{price.toFixed(2)} €</span>
      </div>
      <p>{desc}</p>
    </article>
  );
}
app/menu/page.jsNouveau fichier
import { menuItems } from "../../data/menu";
import MenuCard from "../../components/MenuCard";

export default function MenuPage() {
  return (
    <main>
      <h1>Notre carte</h1>
      {menuItems.map((item) => (
        <MenuCard
          key={item.id}
          name={item.name}
          price={item.price}
          desc={item.desc}
        />
      ))}
    </main>
  );
}

Racontez le flux à voix haute, c'est la boucle centrale du front-end moderne : fichier de données → import du tableau → .map() dessus → un composant par élément → les props remplissent le composant. Chaque grille de produits, page d'équipe ou tableau de prix que vous construirez un jour est ce même motif avec un autre CSS.

Pourquoi key={item.id} ?

React a besoin d'une identité stable pour chaque élément d'une liste, afin de mettre à jour le bon quand les données changent. Utilisez un id venant des données. Évitez l'index du tableau comme key ; il se comporte mal quand les éléments sont réordonnés ou supprimés.

Exercice 09~40 min

La page pilotée par les données

Chapitre 12

Les métadonnées : titres, descriptions et l'onglet du navigateur

Objectif : donner à chaque page son propre titre et sa description, que Google et les réseaux sociaux lisent.

Les métadonnées sont des informations sur la page : le titre dans l'onglet du navigateur, la description que Google affiche sous un résultat de recherche. Dans Next.js, vous n'écrivez jamais de balises <head> à la main ; vous exportez un objet metadata et Next.js génère les balises.

Vous avez déjà des métadonnées pour tout le site dans app/layout.js. Chaque page peut exporter les siennes, qui remplacent celles du layout pour cette page :

app/menu/page.jsÀ ajouter au-dessus du composant
export const metadata = {
  title: "Notre carte | Le Petit Café",
  description: "Espresso, cappuccino et viennoiseries fraîches au cœur de la ville.",
};

export default function MenuPage() {
  // ...identique à avant
}

Les règles pratiques dont vos futurs collègues SEO vous remercieront :

  • Chaque page a un titre unique, au format Nom de la page | Nom du site.
  • La description est une phrase honnête et précise. C'est votre publicité dans les résultats de recherche.
Exercice 10~10 min

Nommez chaque page

Partie 3 · Mise en ligne

Chapitre 13

L'export statique : transformer le projet en un dossier de fichiers

Objectif : compiler le site en fichiers HTML/CSS/JS purs, hébergeables n'importe où.

Un seul changement de configuration

Dites à Next.js que vous voulez un export statique. Ouvrez next.config.mjs et ajoutez deux réglages :

next.config.mjsModifier
/** @type {import('next').NextConfig} */
const nextConfig = {
  output: "export",
  images: { unoptimized: true },
};

export default nextConfig;
  • output: "export" signifie : au moment du build, génère un dossier de fichiers statiques finis.
  • images: { unoptimized: true }, c'est la promesse du chapitre 9 : le redimensionnement d'images à la volée exige un serveur, un site statique n'en a pas, donc on désactive cette seule fonctionnalité.

Compilez

TerminalVous tapez ça
$ npm run build

Route (app)
┌ ○ /
├ ○ /about
├ ○ /contact
└ ○ /menu

○  (Static)  prerendered as static content

Chaque cercle ○ (Static) est une page pré-construite en HTML. Le résultat atterrit dans un nouveau dossier appelé out/ :

out/ · ce dossier EST votre site web
out/
index.htmlla page d'accueil
about.html/about
menu.html/menu
_next/les bundles CSS et JS
images/copié depuis public/

Ouvrez out/about.html dans votre éditeur et regardez-le. C'est du vrai HTML fini contenant votre texte. Voilà ce que « statique » voulait dire au chapitre 1 : le travail s'est fait sur votre machine au moment du build, le navigateur du visiteur reçoit des fichiers instantanés.

Prévisualiser et héberger

Pour prévisualiser le site compilé en local :

TerminalVous tapez ça
$ npx serve out

Pour le mettre sur Internet, envoyez le contenu de out/ sur n'importe quel hébergeur statique. Options gratuites : glissez le dossier sur netlify.com/drop, ou poussez le projet sur GitHub et importez-le dans Vercel ou Cloudflare Pages (ils lancent npm run build pour vous à chaque push). Aucun serveur à gérer, rien à maintenir, rien à se faire pirater à 3 h du matin.

Ce qu'un export statique ne peut pas faire

Pas de système de connexion, pas d'écriture en base de données, pas de traitement de formulaire sur votre propre serveur (les formulaires passent par un service externe comme Formspree, ou une fonctionnalité de l'hébergeur comme Netlify Forms). Quand un projet a besoin de tout ça, on déploie la même application Next.js sur un serveur Node au lieu de l'exporter, et on débloque ses fonctionnalités serveur. Même framework, monde plus grand : c'est un cours pour plus tard.

Exercice 11~15 min

Livrez le site d'entraînement

Chapitre 14 · Le vrai projet

Construisez le site d'une vraie entreprise

Objectif : livrer seul un site statique complet pour un vrai client, du dossier vide jusqu'au build exporté. C'est votre livrable de fin de stage.

Ici, on ne s'entraîne plus. Votre formateur vous remet le brief d'une vraie entreprise : son nom, son activité, ses textes, son logo et ses photos. Votre travail des jours 7 à 12 est de transformer ce contenu en site web fini, en appliquant exactement ce que vous avez appris. Construisez-le de zéro dans un nouveau projet (ne réutilisez pas le projet d'entraînement ; repartir d'une page blanche fait partie du métier). Essayez de travailler sans relire les chapitres, et traitez-les comme votre documentation quand vous bloquez.

Les pages attendues

Le contenu exact vient du brief de votre formateur, mais un site d'entreprise suit presque toujours ce plan. Adaptez les noms si le brief le demande :

PageURLDoit contenir
Accueil/Grand titre avec le nom de l'entreprise, une photo, un court texte de présentation, un Link stylé en bouton vers les services
Services/servicesLes services ou produits de l'entreprise issus d'un fichier de données via .map(), chacun en carte stylée
À propos/aboutL'histoire de l'entreprise, une section équipe depuis un fichier de données, et 3 questions FAQ qui s'ouvrent et se ferment
Contact/contactAdresse, horaires (depuis un fichier de données), e-mail, et un lien externe vers une carte

Exigences pour tout le site (c'est sur ça que vous serez évalués) :

  • Nav et footer sur chaque page, via le layout racine, jamais répétés dans un fichier de page.
  • Chaque composant stylé avec son propre CSS Module ; seulement les fondations dans globals.css.
  • Chaque image via <Image> avec un vrai texte alt.
  • Des metadata uniques sur chaque page.
  • Exactement un fichier dans tout le projet contient "use client" (l'élément FAQ).
  • Le build passe avec npm run build et le site fonctionne servi depuis out/.

Structure de projet suggérée

site-entreprise/ · structure cible
app/
layout.jsNav + footer + métadonnées par défaut
page.jsAccueil
globals.css
services/page.js
about/page.js
contact/page.js
components/Nav, Footer, ServiceCard, TeamMember, FaqItem + leurs fichiers .module.css
data/services.js, team.js, infos.js (adresse, horaires...)
public/images/les photos et le logo fournis dans le brief

Un jalon par jour

Les professionnels ne construisent pas tout d'un coup. Un jalon par jour, vérifié dans le navigateur avant de passer au suivant. Si un jalon est fini en avance, prenez de l'avance sur le suivant. Cochez au fur et à mesure :

Checklist du vrai projetJours 7 à 12

Du dossier vide au site livré

Objectifs bonus, seulement si vous finissez en avance

  • Ajoutez une page 404 personnalisée avec app/not-found.js.
  • Groupez les services par catégorie - indice : deux tableaux, ou .filter() avant .map().

Comment votre formateur évaluera le projet

Pas au pixel près. Les questions de la revue sont : le layout est-il écrit une seule fois ? Le contenu est-il dans des fichiers de données ? Les styles sont-ils dans des modules ? "use client" est-il utilisé exactement une fois et au bon endroit ? Le build passe-t-il ? Ces cinq réponses montrent si vous pensez en Next.js.

Annexes

Annexe A

Anti-sèche

Commandes

  • npx create-next-app@latest nom nouveau projet
  • npm run dev développer sur localhost:3000
  • npm run build compiler pour la production
  • npx serve out prévisualiser l'export statique
  • Ctrl + C arrêter le serveur

Routing

  • Dossier dans app/ = segment d'URL
  • page.js = la page à cette URL
  • layout.js = cadre partagé, affiche {children}
  • not-found.js = 404 personnalisée

Imports quotidiens

  • import Link from "next/link"
  • import Image from "next/image"
  • import { useState } from "react"
  • import styles from "./X.module.css"

Pièges du JSX

  • className, pas class
  • Un seul élément racine par return (ou <>...</>)
  • Fermez chaque balise : <Image />
  • { } = du JavaScript dans le balisage
  • key sur chaque élément d'un .map()

Server vs Client

  • Défaut = Server Component (rapide, statique)
  • Clics ou state ? "use client" en ligne 1
  • Gardez les composants client petits et bas dans l'arbre

Export statique

  • output: "export" dans next.config.mjs
  • images: { unoptimized: true }
  • Résultat dans out/, hébergeable partout

Annexe B

Les erreurs courantes, décodées

L'erreur ditÇa veut direSolution
« npm: command not found »Node.js n'est pas installé, ou le terminal était ouvert pendant l'installationInstallez Node LTS, puis ouvrez un nouveau terminal
« Could not read package.json »Vous êtes dans le mauvais dossierFaites cd vers le dossier du projet d'abord
« X is not defined »Vous utilisez un composant ou une fonction sans l'importerAjoutez la ligne import en haut
« Module not found: Can't resolve '../components/Nav' »Le chemin d'import ou le nom du fichier est fauxComptez les sauts ../ ; vérifiez l'orthographe et les majuscules
« You're importing a component that needs useState... »Du state ou des événements dans un Server ComponentAjoutez "use client" en ligne 1 de ce fichier
« Adjacent JSX elements must be wrapped... »Votre return a deux éléments racinesEnveloppez-les dans une <div> ou <>...</>
« Each child in a list should have a unique 'key' prop »Un .map() sans keysAjoutez key={item.id} à l'élément mappé le plus externe
La page affiche 404 alors que le dossier existeLe fichier à l'intérieur ne s'appelle pas exactement page.jsRenommez-le ; seul page.js crée une URL
L'image affiche une icône casséeMauvais chemin dans srcLe chemin part de public/ : le fichier public/images/a.jpg devient src="/images/a.jpg"
« Port 3000 already in use »Un ancien serveur de dev tourne encoreRetrouvez ce terminal et faites Ctrl + C, ou acceptez le port 3001 proposé

Méthode générale de débogage : lisez la première erreur (les suivantes ne sont souvent que ses échos), notez le nom de fichier et le numéro de ligne mentionnés, et relisez exactement cette ligne. Neuf fois sur dix, c'est une faute de frappe, un import manquant ou une balise non fermée.

Annexe C

Glossaire

Composant
Une fonction JavaScript avec une majuscule qui retourne du JSX. La brique de base réutilisable de React.
JSX
La syntaxe qui ressemble à du HTML dans les composants. Les accolades y insèrent du JavaScript.
Props
Des données passées à un composant comme des attributs HTML, pour le réutiliser avec des contenus différents.
State
La valeur changeante propre à un composant, créée avec useState. La modifier réaffiche le composant.
App Router
Le système de routing de Next.js où les dossiers de app/ définissent les URLs.
Layout
Un cadre partagé autour des pages. Affiche chaque page là où il écrit {children}.
Server Component
Le défaut. Rendu en HTML à l'avance ; aucune interactivité propre.
Client Component
Un composant marqué "use client" dont le JavaScript s'exécute dans le navigateur pour l'interactivité.
CSS Module
Un fichier .module.css dont les classes sont privées au composant qui l'importe.
Hot reload
Le serveur de dev qui met le navigateur à jour instantanément quand vous sauvegardez.
Export statique
La compilation du site entier en fichiers purs dans out/, hébergeables sur n'importe quel hébergeur statique.
Build
Le processus (npm run build) qui transforme votre code source en fichiers de production optimisés.
localhost:3000
Votre propre ordinateur qui sert le site pendant le développement. Visible par vous seul.
npm
Le gestionnaire de paquets qui installe les bibliothèques et lance les scripts du projet.