Mode d'emploi — de zĂ©ro Ă  dĂ©ployĂ©

Vitrine

Site vitrine pour prĂ©senter une activitĂ© : services, Ă  propos, contact. Pas de compte utilisateur, pas de base de donnĂ©es — le strict nĂ©cessaire.

Sommaire
01Initialiser le projet Next.js
02Structurer les pages
03Habillage — Tailwind & shadcn/ui
04Formulaire de contact
05SEO de base
06DĂ©ploiement — Vercel
RĂšgle du jeu : tu tapes chaque commande toi-mĂȘme dans ton terminal, dans l'ordre. Tu ne passes Ă  l'Ă©tape suivante que quand la case « vĂ©rification » est cochĂ©e. Si une commande plante, copie-colle l'erreur exacte — on corrige ensemble, tu ne devines pas.

RĂ©utilisable vs spĂ©cifique : les Ă©tapes rĂ©utilisable sont valables pour n'importe quel projet de ta stack. Les Ă©tapes spĂ©cifique sont propres Ă  un site vitrine — adapte le contenu (pages, textes) au tien.
📖 C'est quoi chaque techno (Next.js, Tailwind, shadcn/ui...) ? Le lexique complet est sur la page d'accueil →
01
Réutilisable

Initialiser le projet Next.js

Un projet Next.js qui dĂ©marre en local, avec Tailwind et shadcn/ui prĂȘts Ă  l'emploi.

Prérequis : Node.js installé. Terminal ouvert dans le dossier du projet.

  1. Installe pnpm si besoin
    npm install -g pnpm
    pnpm est le gestionnaire de paquets choisi pour ce projet — plus rapide et plus Ă©conome en espace disque que npm.
    👁 Comment voir le rĂ©sultat : tape pnpm -v. Un numĂ©ro de version s'affiche (ex. 9.12.0) — sinon l'installation a Ă©chouĂ©.
  2. Crée le projet Next.js
    pnpm create next-app@latest . --typescript --tailwind --eslint --app --src-dir=false --import-alias "@/*"
    Le nom du dossier ne doit pas contenir de majuscules (contrainte npm). S'il en contient, crée le projet dans un dossier temporaire au nom valide puis déplace tout son contenu dans ton dossier de travail.
    👁 Comment voir le rĂ©sultat : tape ls. Tu dois voir apparaĂźtre app/, package.json, tailwind.config.ts — la commande a rempli ton dossier de fichiers.
  3. Initialise shadcn/ui
    pnpm dlx shadcn@latest init
    Ça crĂ©e components.json et lib/utils.ts, et prĂ©pare Tailwind pour recevoir des composants shadcn/ui prĂȘts Ă  copier.
    👁 Comment voir le rĂ©sultat : tape ls components.json lib/utils.ts — les deux fichiers doivent exister, sans message d'erreur « No such file ».
  4. Crée l'arborescence du projet
    mkdir -p lib/auth lib/db lib/validations prisma testsmkdir lib/auth, lib/db, lib/validations, prisma, tests
    On sĂ©pare dĂšs le dĂ©part : authentification, accĂšs base de donnĂ©es, schĂ©mas de validation. Ça Ă©vite le fichier fourre-tout de 2000 lignes plus tard.
    👁 Comment voir le rĂ©sultat : tape ls lib — les dossiers auth, db, validations doivent apparaĂźtre.
  5. Initialise Git et fais le premier commit
    git init
    git add -A
    git commit -m "chore: init projet Next.js"
    👁 Comment voir le rĂ©sultat : tape git log --oneline — une ligne avec ton message de commit doit s'afficher.
  6. Lance le serveur et vérifie
    pnpm dev
    Ouvre http://localhost:3000. Si tu as une erreur 500 mentionnant un module introuvable (ex. Can't resolve 'xxx') alors qu'il est bien dans package.json : supprime node_modules, pnpm-lock.yaml et .next, relance pnpm install puis pnpm dev. C'est presque toujours une installation incomplĂšte, pas un bug de code.
    👁 Comment voir le rĂ©sultat : dans ton navigateur, ouvre localhost:3000. Tu dois voir la page d'accueil par dĂ©faut de Next.js (logo, liens « Docs », « Deploy »). Le terminal affiche Ready et n'affiche pas d'erreur rouge.
Vérification
02
Spécifique vitrine

Structurer les pages

Une arborescence claire : Accueil, Services, À propos, Contact.

Prérequis : étape 1 validée.

  1. Liste les pages nécessaires avant de coder
    Évite d'improviser l'arborescence au fil de l'eau — note juste les 3-5 pages dont le site a vraiment besoin. Pour ce guide : Accueil, Services, À propos, Contact.
  2. Crée les dossiers des 3 pages restantes
    mkdir -p app/services app/a-propos app/contactmkdir app/services, app/a-propos, app/contact
    app/page.tsx (la page d'accueil) existe dĂ©jĂ  depuis la crĂ©ation du projet Ă  l'Ă©tape 1 — seules les 3 nouvelles sections ont besoin d'un dossier.
    👁 Comment voir le rĂ©sultat : tape ls app — les dossiers services, a-propos et contact doivent apparaĂźtre.
  3. Crée le fichier page.tsx de chaque page
    touch app/services/page.tsx app/a-propos/page.tsx app/contact/page.tsxNew-Item -ItemType File -Force -Path app/services/page.tsx, app/a-propos/page.tsx, app/contact/page.tsx
    Dans le dossier app/ de Next.js, chaque sous-dossier contenant un fichier page.tsx devient une URL du mĂȘme nom.
    👁 Comment voir le rĂ©sultat : tape ls app/services app/a-propos app/contact — chaque dossier doit contenir un fichier page.tsx (vide pour l'instant, il ne s'affichera pas encore).
  4. Ouvre chaque fichier et colle un contenu minimal
    // app/services/page.tsx
    export default function ServicesPage() {
      return (
        <main className="p-8">
          <h1 className="text-2xl font-bold">Nos services</h1>
          <p>Décris ici ce que tu proposes.</p>
        </main>
      );
    }
    Un fichier page.tsx vide fait planter le build (« The default export is not a React Component ») — il lui faut au minimum une fonction exportĂ©e par dĂ©faut qui retourne du JSX. RĂ©pĂšte la mĂȘme structure dans app/a-propos/page.tsx (fonction AProposPage) et app/contact/page.tsx (fonction ContactPage — le vrai formulaire arrive Ă  l'Ă©tape 3, un simple titre suffit pour l'instant).
    👁 Comment voir le rĂ©sultat : ouvre localhost:3000/services, /a-propos et /contact dans le navigateur. Chaque URL doit afficher son contenu — pas de page « 404 This page could not be found » ni d'erreur rouge dans le terminal.
  5. Crée le dossier et les fichiers du header et du footer
    mkdir -p components && touch components/header.tsx components/footer.tsxNew-Item -ItemType Directory -Force -Path components; New-Item -ItemType File -Force -Path components/header.tsx, components/footer.tsx
    👁 Comment voir le rĂ©sultat : tape ls components — header.tsx et footer.tsx doivent apparaĂźtre.
  6. Colle le contenu du header et du footer
    // components/header.tsx
    import Link from "next/link";
    
    export default function Header() {
      return (
        <header className="border-b p-4 flex gap-4">
          <Link href="/">Accueil</Link>
          <Link href="/services">Services</Link>
          <Link href="/a-propos">À propos</Link>
          <Link href="/contact">Contact</Link>
        </header>
      );
    }
    // components/footer.tsx
    export default function Footer() {
      return (
        <footer className="border-t p-4 text-sm text-center">
          © {new Date().getFullYear()} Ton Activité
        </footer>
      );
    }
    Ces deux composants seront importĂ©s une seule fois dans app/layout.tsx Ă  l'Ă©tape suivante — Ă©vite de dupliquer la navigation sur chaque page.
  7. Importe le header et le footer dans app/layout.tsx
    // app/layout.tsx
    import Header from "@/components/header";
    import Footer from "@/components/footer";
    
    // ... dans le return, à l'intérieur de <body> :
    <body>
      <Header />
      {children}
      <Footer />
    </body>
    Next.js applique app/layout.tsx Ă  toutes les pages — c'est le seul endroit oĂč dĂ©clarer le header et le footer.
    👁 Comment voir le rĂ©sultat : retourne sur localhost:3000 — ton en-tĂȘte et ton pied de page doivent apparaĂźtre, et rester identiques si tu changes de page.
  8. Ajoute les composants shadcn/ui nécessaires
    pnpm dlx shadcn@latest add button card
    👁 Comment voir le rĂ©sultat : tape ls components/ui — button.tsx et card.tsx doivent apparaĂźtre, prĂȘts Ă  ĂȘtre importĂ©s dans tes pages.
Vérification
03
Réutilisable

Habillage — Tailwind & shadcn/ui

Un rendu visuel cohérent sur tout le site, et une méthode simple pour le modifier plus tard.

Prérequis : étape 2 validée.

  1. Comprends oĂč vit le style
    Il n'y a pas un fichier .css par page. Deux niveaux seulement : les variables de thĂšme globales dans app/globals.css (couleurs, arrondi — gĂ©nĂ©rĂ©es par shadcn init Ă  l'Ă©tape 1, chargĂ©es une seule fois par app/layout.tsx), et les classes Tailwind Ă©crites directement dans le className de chaque composant.
  2. Personnalise les couleurs du thĂšme
    Ouvre app/globals.css — repĂšre le bloc :root { ... } gĂ©nĂ©rĂ© par shadcn init, qui contient des variables comme --primary ou --background. Change leurs valeurs directement dans ce fichier.
    👁 Comment voir le rĂ©sultat : modifie la valeur de --primary, enregistre, recharge localhost:3000 — n'importe quel composant shadcn/ui (le Button ajoutĂ© Ă  l'Ă©tape prĂ©cĂ©dente) doit changer de couleur automatiquement, sans toucher au code des pages.
  3. Crée une mise en page cohérente, réutilisée sur chaque page
    touch components/container.tsxNew-Item -ItemType File -Force -Path components/container.tsx
    // components/container.tsx
    export default function Container({ children }: { children: React.ReactNode }) {
      return (
        <div className="max-w-5xl mx-auto px-4 py-12">
          {children}
        </div>
      );
    }
    Sans ça, tu rĂ©pĂštes les mĂȘmes classes d'espacement (max-w-5xl mx-auto px-4 py-12) dans chaque fichier page.tsx — un seul endroit Ă  modifier si tu changes la largeur ou les marges du site.
    👁 Comment voir le rĂ©sultat : enveloppe le contenu retournĂ© par app/page.tsx, app/services/page.tsx, etc. avec <Container>...</Container> — chaque page doit s'afficher centrĂ©e, avec la mĂȘme marge, une fois rechargĂ©e.
  4. Remplace le HTML brut par les composants shadcn/ui déjà installés
    // avant
    <button className="bg-blue-500 text-white px-4 py-2 rounded">Envoyer</button>
    
    // aprĂšs
    import { Button } from "@/components/ui/button";
    <Button>Envoyer</Button>
    Le composant Button hĂ©rite automatiquement des variables de thĂšme dĂ©finies plus haut — un <button> HTML brut, non. Change --primary et seul le premier ne suivra pas.
  5. Pour modifier le style plus tard
    Garde pnpm dev lancĂ© en continu — le rechargement Ă  chaud applique tes changements dans le navigateur dĂšs que tu sauvegardes, sans redĂ©marrer le serveur. Ouvre le fichier de la page ou du composant concernĂ©, change les classes dans className, enregistre. Pour ajouter un nouveau composant shadcn/ui : pnpm dlx shadcn@latest add <nom> (liste sur ui.shadcn.com). Pour savoir ce que fait une classe (p-4, rounded-lg, text-xl...), consulte le lexique ou tailwindcss.com/docs.
Vérification
04
Spécifique vitrine

Formulaire de contact

Recevoir un message par email, sans base de données à gérer.

Prérequis : étape 3 validée.

  1. Choisis un service d'envoi d'email
    Pas besoin de stocker le message en base pour un simple formulaire de contact — un envoi direct par email suffit. Resend a un plan gratuit largement suffisant pour dĂ©marrer.
  2. Installe le SDK
    pnpm add resend
    👁 Comment voir le rĂ©sultat : ouvre package.json — resend doit apparaĂźtre dans dependencies.
  3. Ajoute la clé API dans .env
    # .env
    RESEND_API_KEY="ta-clé"
    👁 Comment voir le rĂ©sultat : pas d'effet visible tout de suite — cette clĂ© sera testĂ©e concrĂštement Ă  l'Ă©tape suivante, quand le formulaire enverra un vrai email.
  4. Écris la Server Action d'envoi
    "use server";
    import { Resend } from "resend";
    const resend = new Resend(process.env.RESEND_API_KEY);
    
    export async function sendContact(formData: FormData) {
      const email = formData.get("email");
      const message = formData.get("message");
      await resend.emails.send({
        from: "site@tondomaine.com",
        to: "toi@tondomaine.com",
        subject: "Nouveau message du site",
        text: `${email}\n\n${message}`,
      });
    }
    Valide email et message avec Zod avant l'envoi — bloque les champs vides ou les emails mal formĂ©s.
    👁 Comment voir le rĂ©sultat : remplis le formulaire sur localhost:3000/contact avec un vrai email et envoie-le. VĂ©rifie ta boĂźte de rĂ©ception (et les spams) — le message doit arriver en quelques secondes.
Vérification
05
Réutilisable

SEO de base

Que le site soit correctement référencé et compris par Google.

Prérequis : étape 4 validée.

  1. Renseigne les métadonnées
    // app/layout.tsx
    export const metadata = {
      title: "Nom de ton activité",
      description: "Une phrase claire sur ce que tu proposes.",
    };
    C'est ce texte qui s'affiche dans l'onglet du navigateur et dans les résultats Google.
    👁 Comment voir le rĂ©sultat : recharge localhost:3000 et regarde l'onglet du navigateur — le nouveau titre doit y ĂȘtre affichĂ© Ă  la place de « create-next-app ».
  2. Crée un sitemap et un robots.txt
    touch app/sitemap.ts app/robots.tsNew-Item -ItemType File -Force -Path app/sitemap.ts, app/robots.ts
    Deux fichiers spéciaux Next.js qui indiquent à Google quelles pages explorer.
  3. Colle le contenu de chaque fichier
    // app/sitemap.ts
    import { MetadataRoute } from "next";
    
    export default function sitemap(): MetadataRoute.Sitemap {
      const base = "https://tondomaine.vercel.app";
      return ["", "/services", "/a-propos", "/contact"].map((path) => ({
        url: `${base}${path}`,
        lastModified: new Date(),
      }));
    }
    // app/robots.ts
    import { MetadataRoute } from "next";
    
    export default function robots(): MetadataRoute.Robots {
      return {
        rules: { userAgent: "*", allow: "/" },
        sitemap: "https://tondomaine.vercel.app/sitemap.xml",
      };
    }
    Remplace tondomaine.vercel.app par ton URL réelle une fois qu'elle est connue (étape 5).
    👁 Comment voir le rĂ©sultat : ouvre localhost:3000/sitemap.xml et localhost:3000/robots.txt — chacune doit afficher du texte structurĂ©, pas une page d'erreur.
  4. Utilise next/image pour toutes les images
    Compression et chargement diffĂ©rĂ© automatiques — un site plus rapide se classe mieux.
    👁 Comment voir le rĂ©sultat : clic droit sur une image affichĂ©e → « Inspecter » — la balise doit avoir un attribut srcset gĂ©nĂ©rĂ© automatiquement, avec plusieurs tailles d'image.
Vérification
06
Réutilisable

DĂ©ploiement — Vercel

Une URL publique et fonctionnelle.

Prérequis : étape 5 validée.

  1. Pousse le code sur GitHub
    git remote add origin URL-DE-TON-DEPOT
    git push -u origin master
    👁 Comment voir le rĂ©sultat : rafraĂźchis la page du dĂ©pĂŽt sur GitHub dans ton navigateur — tes fichiers doivent y apparaĂźtre.
  2. Importe le projet sur Vercel
    Sur vercel.com → Add New → Project → sĂ©lectionne le dĂ©pĂŽt GitHub.
    👁 Comment voir le rĂ©sultat : le tableau de bord Vercel passe de « Building » Ă  « Ready » (quelques dizaines de secondes), avec un lien de prĂ©visualisation cliquable.
  3. Ajoute RESEND_API_KEY dans les variables d'environnement
    Settings → Environment Variables — sans ça le formulaire de contact ne fonctionnera pas en production.
    👁 Comment voir le rĂ©sultat : pas d'effet visible immĂ©diatement — redĂ©ploie (bouton « Redeploy ») puis teste le formulaire en production Ă  l'Ă©tape suivante.
  4. Déploie et vérifie en ligne
    Ouvre l'URL fournie par Vercel, teste le formulaire de contact pour de vrai.
    👁 Comment voir le rĂ©sultat : le site s'affiche sur l'URL *.vercel.app, et un message envoyĂ© depuis ce formulaire en ligne arrive bien dans ta boĂźte mail — comme en local, mais pour de vrai.
Vérification