Next.js et Supabase
Créer une application web avec Next.js et Supabase, en respectant les bonnes pratiques de sécurité, propreté du code, et en utilisant TypeScript ainsi que shadcn-ui.
🚀 Objectif
Nous allons créer une application Next.js avec :
- Next.js (framework React pour le rendu côté serveur et statique)
- Supabase (alternative open-source à Firebase pour l'authentification et la base de données)
- TypeScript (pour la sécurité et la maintenabilité du code)
- shadcn-ui (bibliothèque de composants UI basée sur Radix UI)
- les bonnes pratiques de sécurité (pratiques de sécurité pour protéger les données et éviter les vulnérabilités)
🛠️ 1 : Installer Next.js
Tout d'abord, installons Next.js avec TypeScript :
npx create-next-app@latest my-app --typescript
Need to install the following packages:
create-next-app@15.1.7
Ok to proceed? (y)
✔ Would you like to use ESLint? … No / Yes
✔ Would you like to use Tailwind CSS? … No / Yes
✔ Would you like your code inside a `src/` directory? … No / Yes
✔ Would you like to use App Router? (recommended) … No / Yes
✔ Would you like to use Turbopack for `next dev`? … No / Yes
✔ Would you like to customize the import alias (`@/*` by default)? … No / Yes
cd my-app
Ensuite, installons les dépendances essentielles :
npm install @supabase/supabase-js @radix-ui/react-icons class-variance-authority clsx tailwind-merge zod react-hook-form
Ces dépendances servent à :
- @supabase/supabase-js : pour interagir avec Supabase
- @radix-ui/react-icons : pour les icônes pour l’UI
- class-variance-authority, clsx, tailwind-merge : pour gérer les classes CSS proprement
- zod : pour la validation de données
- react-hook-form : pour gérer les formulaires de manière efficace
🎨 2 : Ajouter et configurer Tailwind CSS
Supprimez le fichier tailwind.config.js (inutile, car nous utilisons Typescript) :
rm tailwind.config.js
Pour que Tailwind utilise le fichier de configuration TypeScript (.ts
et non pas .js
),
ajoutez la ligne :
"tailwind": "tailwindcss -c tailwind.config.ts"
dans package.json :
"scripts": {
"dev": "next dev --turbopack",
"build": "next build",
"start": "next start",
"lint": "next lint",
"tailwind": "tailwindcss -c tailwind.config.ts"
},
}
Installez Tailwind CSS :
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
Vérifiez le fichier tailwind.config.ts :
import { type Config } from 'tailwindcss'
const config: Config = {
content: [
"./pages/**/*.{js,ts,jsx,tsx}",
"./components/**/*.{js,ts,jsx,tsx}",
"./app/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
export default config
Vérifiez que le fichier app/globals.css contienne bien ces 3 lignes :
@tailwind base;
@tailwind components;
@tailwind utilities;
🏗️ 3 : Installer et configurer shadcn-ui
Installez shadcn-ui :
npx shadcn@latest init
Ajoutez un composant UI, par exemple un bouton :
npx shadcn@latest add button
🗄️ 4 : Configurer Supabase
Créez un compte sur Supabase et un nouveau projet.
Dans .env.local, ajoutez vos clés Supabase :
NEXT_PUBLIC_SUPABASE_URL=your-supabase-url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
Créez un fichier lib/supabase.ts pour initialiser Supabase :
import { createClient } from '@supabase/supabase-js'
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
export const supabase = createClient(supabaseUrl, supabaseAnonKey)
🔐 5 : Sécuriser l'authentification
Ajoutons un système d'authentification sécurisé avec Supabase.
Créez un fichier auth.ts dans /lib/ :
import { supabase } from "./supabase"
export const signInWithEmail = async (email: string, password: string) => {
const { data, error } = await supabase.auth.signInWithPassword({ email, password })
if (error) throw new Error(error.message)
return data.user
}
export const signUpWithEmail = async (email: string, password: string) => {
const { data, error } = await supabase.auth.signUp({ email, password })
if (error) throw new Error(error.message)
return data.user
}
export const signOut = async () => {
await supabase.auth.signOut()
}
Ensuite, créons une page de connexin dans /app/login/page.tsx :
"use client"
import { useState } from "react"
import { signInWithEmail } from "@/lib/auth"
import { Button } from "@/components/ui/button"
export default function Login() {
const [email, setEmail] = useState("")
const [password, setPassword] = useState("")
const [error, setError] = useState<string | null>(null)
const handleLogin = async () => {
try {
await signInWithEmail(email, password)
alert("Connexion réussie !")
} catch (err) {
setError((err as Error).message)
}
}
return (
<div className="flex flex-col items-center justify-center min-h-screen">
<input
type="email"
placeholder="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
className="border p-2 rounded"
/>
<input
type="password"
placeholder="Mot de passe"
value={password}
onChange={(e) => setPassword(e.target.value)}
className="border p-2 rounded mt-2"
/>
<Button onClick={handleLogin} className="mt-4">Se connecter</Button>
{error && <p className="text-red-500 mt-2">{error}</p>}
</div>
)
}
🔒 6 : Sécuriser les données
Ajoutez le code suivant dans un nouveau fichier /hooks/useAuth.ts pour récupérer l’utilisateur connecté :
"use client"
import { useEffect, useState } from "react"
import { supabase } from "@/lib/supabase"
import { User } from "@supabase/supabase-js"
export function useAuth() {
const [user, setUser] = useState<User | null>(null)
const [loading, setLoading] = useState(true)
useEffect(() => {
const getUser = async () => {
const { data: { user } } = await supabase.auth.getUser()
setUser(user)
setLoading(false)
}
getUser()
}, [])
return { user, loading }
}
Pour protéger les pages, remplacez le code du fichier layout.tsx :
import { AuthProvider } from "@/components/AuthProvider"
import './globals.css' // Tailwind CSS
export const metadata = {
title: 'Mon application',
description: 'Application au top !',
}
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="fr">
<head>
<meta charSet="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Mon application</title>
<meta name="description" content="Application au top !" />
<meta name="author" content="Mon nom" />
<link rel="icon" href="/favicon.ico" />
</head>
<body>
<AuthProvider>
{children}
</AuthProvider>
</body>
</html>
)
}
✔️ 7 : Démarrage en mode développement
npm run dev