React - Next.js et les Meta-Frameworks
Une fois que tu maîtrises un peu React, je te CONSEILLE FORTEMENT de passer sur un meta-framework. Next.js, Astro, Remix... peu importe lequel, ça va révolutionner ta façon de développer !
Pourquoi des Meta-Frameworks ?
React seul, c'est limité
React, c'est juste une librairie pour créer des interfaces. Mais pour une vraie application web, il te faut :
- 🗺️ Routing : gérer les pages et navigation
- ⚡ Server-Side Rendering (SSR) : SEO et performance
- 🏗️ Static Site Generation (SSG) : sites ultra rapides
- 🖼️ Optimisation d'images : formats modernes, lazy loading
- 📦 Bundle optimization : code splitting automatique
- 🔧 Configuration : Webpack, Babel, TypeScript...
React + Vite = Pas assez pour la prod
// ❌ Avec React/Vite classique - tu dois tout faire à la main
function App() {
return (
<div>
{/* Comment tu fais du routing ? */}
{/* Comment tu optimises les images ? */}
{/* Comment tu gères le SEO ? */}
{/* Comment tu fais du SSR ? */}
</div>
)
}
// ✅ Avec Next.js - tout est automatique !
export default function HomePage() {
return (
<div>
<Head>
<title>Ma super page - SEO automatique !</title>
</Head>
<Image
src="/photo.jpg"
alt="Photo optimisée automatiquement"
width={500}
height={300}
/>
</div>
)
}
// SSG automatique avec cette fonction
export async function getStaticProps() {
const data = await fetch('https://api.example.com/data')
return { props: { data } }
}
Next.js - Le Boss des Meta-Frameworks
Setup ultra simple
npx create-next-app@latest mon-app-nextjs
cd mon-app-nextjs
npm run dev
Boom ! Ton app Next.js tourne sur http://localhost:3000
Structure du projet
mon-app-nextjs/
├── app/ # 🆕 App Router (Next.js 13+)
│ ├── layout.tsx # Layout global
│ ├── page.tsx # Page d'accueil
│ ├── about/
│ │ └── page.tsx # Route /about
│ └── blog/
│ ├── page.tsx # Route /blog
│ └── [id]/
│ └── page.tsx # Route dynamique /blog/123
├── public/ # Fichiers statiques
├── components/ # Tes composants
└── next.config.js # Configuration Next.js
Les Super-Pouvoirs de Next.js
1. App Router - Routing Moderne
// app/page.tsx - Page d'accueil
export default function HomePage() {
return <h1>Accueil</h1>
}
// app/about/page.tsx - Page /about
export default function AboutPage() {
return <h1>À propos</h1>
}
// app/blog/[id]/page.tsx - Route dynamique
export default function BlogPost({ params }) {
return <h1>Article {params.id}</h1>
}
// app/layout.tsx - Layout global
export default function RootLayout({ children }) {
return (
<html>
<body>
<nav>
<Link href="/">Accueil</Link>
<Link href="/about">À propos</Link>
</nav>
{children}
</body>
</html>
)
}
2. Server Components - Performance de malade
// ✅ Server Component - s'execute sur le serveur
async function ProductsList() {
// Cette requête se fait côté serveur !
const products = await fetch('https://api.example.com/products')
return (
<div>
{products.map(product => (
<ProductCard key={product.id} product={product} />
))}
</div>
)
}
// ✅ Client Component - pour l'interactivité
'use client'
import { useState } from 'react'
function ProductCard({ product }) {
const [liked, setLiked] = useState(false)
return (
<div>
<h3>{product.name}</h3>
<button onClick={() => setLiked(!liked)}>
{liked ? '❤️' : '🤍'}
</button>
</div>
)
}
3. Static Site Generation (SSG)
// app/blog/[id]/page.tsx
export default function BlogPost({ params }) {
return <h1>Article {params.id}</h1>
}
// Génère toutes les pages statiquement au build
export async function generateStaticParams() {
const posts = await fetch('https://api.example.com/posts')
return posts.map(post => ({
id: post.id.toString()
}))
}
4. Server Actions - Full-stack sans API
// actions.ts
'use server'
export async function createPost(formData) {
const title = formData.get('title')
const content = formData.get('content')
// Sauvegarde en base directement !
await db.posts.create({ title, content })
redirect('/blog')
}
// components/CreatePost.tsx
import { createPost } from './actions'
export default function CreatePost() {
return (
<form action={createPost}>
<input name="title" placeholder="Titre" />
<textarea name="content" placeholder="Contenu" />
<button type="submit">Publier</button>
</form>
)
}
5. Optimisations Automatiques
import Image from 'next/image'
import Link from 'next/link'
export default function HomePage() {
return (
<div>
{/* Image optimisée automatiquement */}
<Image
src="/hero.jpg"
alt="Hero"
width={800}
height={400}
priority // Charge en priorité
/>
{/* Prefetch automatique des liens */}
<Link href="/about">À propos</Link>
{/* Code splitting automatique */}
<DynamicComponent />
</div>
)
}
Exemples Pratiques
Blog avec SSG
// app/blog/page.tsx - Liste des articles
export default async function BlogPage() {
const posts = await fetch('https://api.example.com/posts')
return (
<div>
<h1>Mon Blog</h1>
{posts.map(post => (
<article key={post.id}>
<h2>
<Link href={`/blog/${post.id}`}>
{post.title}
</Link>
</h2>
<p>{post.excerpt}</p>
</article>
))}
</div>
)
}
// app/blog/[id]/page.tsx - Article individuel
export default async function BlogPost({ params }) {
const post = await fetch(`https://api.example.com/posts/${params.id}`)
return (
<article>
<h1>{post.title}</h1>
<div dangerouslySetInnerHTML={{ __html: post.content }} />
</article>
)
}
// Génération statique de tous les articles
export async function generateStaticParams() {
const posts = await fetch('https://api.example.com/posts')
return posts.map(post => ({ id: post.id.toString() }))
}
E-commerce avec Server Actions
// app/products/[id]/page.tsx
import { addToCart } from './actions'
export default async function ProductPage({ params }) {
const product = await fetch(`/api/products/${params.id}`)
return (
<div>
<h1>{product.name}</h1>
<p>Prix: {product.price}€</p>
<form action={addToCart}>
<input type="hidden" name="productId" value={product.id} />
<input type="number" name="quantity" defaultValue={1} />
<button type="submit">Ajouter au panier</button>
</form>
</div>
)
}
// actions.ts
'use server'
import { cookies } from 'next/headers'
export async function addToCart(formData) {
const productId = formData.get('productId')
const quantity = formData.get('quantity')
// Récupère le panier depuis les cookies
const cart = cookies().get('cart')?.value || '[]'
const cartItems = JSON.parse(cart)
// Ajoute le produit
cartItems.push({ productId, quantity: parseInt(quantity) })
// Sauvegarde dans les cookies
cookies().set('cart', JSON.stringify(cartItems))
redirect('/cart')
}
Configuration Avancée
next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
// Optimisations d'images
images: {
domains: ['example.com', 'cdn.example.com'],
formats: ['image/webp', 'image/avif'],
},
// Variables d'environnement
env: {
CUSTOM_KEY: process.env.CUSTOM_KEY,
},
// Redirections
async redirects() {
return [
{
source: '/old-page',
destination: '/new-page',
permanent: true,
},
]
},
// Headers de sécurité
async headers() {
return [
{
source: '/(.*)',
headers: [
{
key: 'X-Frame-Options',
value: 'DENY',
},
],
},
]
},
}
module.exports = nextConfig
Middleware pour l'auth
// middleware.ts
import { NextResponse } from 'next/server'
export function middleware(request) {
// Vérifie l'auth pour les pages protégées
if (request.nextUrl.pathname.startsWith('/dashboard')) {
const token = request.cookies.get('auth-token')
if (!token) {
return NextResponse.redirect(new URL('/login', request.url))
}
}
}
export const config = {
matcher: '/dashboard/:path*',
}
Les Alternatives à Next.js
🚀 Astro - Le minimaliste
// Parfait pour les sites avec peu d'interactivité
---
const posts = await fetch('https://api.example.com/posts').then(r => r.json())
---
<html>
<head>
<title>Mon site Astro</title>
</head>
<body>
<h1>Blog</h1>
{posts.map(post => (
<article>
<h2>{post.title}</h2>
<p>{post.excerpt}</p>
</article>
))}
</body>
</html>
🎵 Remix - Le full-stack
// Remix mise tout sur les Web Standards
export async function loader({ params }) {
return json(await getPost(params.id))
}
export async function action({ request }) {
const formData = await request.formData()
await createPost(formData)
return redirect('/posts')
}
export default function Post() {
const post = useLoaderData()
return (
<div>
<h1>{post.title}</h1>
<Form method="post">
<input name="comment" />
<button type="submit">Commenter</button>
</Form>
</div>
)
}
⚡ Vite + React Router - DIY
// Si tu veux tout contrôler toi-même
import { BrowserRouter, Routes, Route } from 'react-router-dom'
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/blog/:id" element={<BlogPost />} />
</Routes>
</BrowserRouter>
)
}
Déployement
Vercel (Créateurs de Next.js)
npm i -g vercel
vercel --prod
Et voilà ! Ton app est en ligne avec HTTPS, CDN, edge functions...
Alternatives
- Netlify : Simple et efficace
- Railway : Full-stack avec base de données
- AWS Amplify : Écosystème AWS complet
- Self-hosted : Docker + votre serveur