Apprends à valider et typer tes variables d'environnement avec Zod pour sécuriser et simplifier l’authentification dans React Router 7.
avec React Router 7
Posez vos questions 24/7 à notre IA experte en React Router 7
Validez vos acquis avec des quiz personnalisés et un feedback instantané
Une app full-stack a besoin de secrets : URL de BDD, clés SMTP, token Stripe... Si l’une de ces valeurs manque ou contient une coquille, ta mise en prod crashe au premier appel réseau - au pire tu exposes tes credentials côté client. La solution ? Valider et typer dès le démarrage grâce à Zod.
Objectifs de la leçon :
process.env
au boot et provoquer un crash explicite en cas d’oubli.process.env
.useEnv()
pour lire les variables « safe » partout côté client.On place toute la logique dans app/server/env.server.ts
.
1import { z } from "zod";23const envServerSchema = z.object({4DATABASE_URL: z.string().min(4),5SMTP_HOST: z.string().min(4),6SMTP_PORT: z.coerce.number(),7SMTP_USER: z.string().min(4),8SMTP_PASSWORD:z.string().min(4),9FRONTEND_URL: z.string().url(),10});1112export const serverEnv = envServerSchema.parse(process.env);
parse(process.env)
déclenche une erreur détaillée si une clé est absente
ou trop courte.z.coerce.number()
transforme "465"
en 465
, pratique pour les
valeurs numériques reçues en string.Pour bénéficier d’un auto-complétion sur process.env
, on étend le type
fourni par Node :
1declare global {2namespace NodeJS {3interface ProcessEnv extends z.infer<typeof envServerSchema> {}4}5}
Tu n’écriras plus jamais
process.env.SMTP_HOST ?? ""
: TypeScript sait que la valeur est présente et de typestring
.
On ne veut pas voir DATABASE_URL
ou SMTP_PASSWORD
dans les DevTools !
Seule la variable FRONTEND_URL
est inoffensive.
On la transmet dans le loader
root :
1export async function loader({ request }: LoaderFunctionArgs) {2const user = await getOptionalUser({ request });34return data({5user,6env: {7FRONTEND_URL: serverEnv.FRONTEND_URL, // 🔐 une seule clé autorisée8},9});10}
useEnv()
ultra simple1import { useRouteLoaderData } from "react-router";23export function useEnv() {4const data = useRouteLoaderData<typeof loader>("root");5return data?.env ?? null; // Renvoie { FRONTEND_URL } ou null6}
Utilisation :
1const { FRONTEND_URL } = useEnv() ?? {};
Aucune dépendance contextuelle, pas de state local : React Router fournit déjà la donnée hydratée depuis le SSR.
1- const url = process.env.DATABSE_URL // 🙀 typo silencieuse2+ const url = serverEnv.DATABASE_URL // 🛑 erreur de compile
Un slug mal orthographié est détecté à la compilation, pas en production.
Ajoute volontairement une clé manquante dans .env
, puis lance :
1npm run dev
1❌ [env.server] Invalid environment variables:2DATABASE_URL is required
L’app refuse de démarrer – tu corriges avant le déploiement.
C’est bien moins coûteux qu’un Cannot connect to "undefined"
reçu par
tes utilisateurs !
1--- app/server/env.server.ts2import { z } from "zod";34const envServerSchema = z.object({5DATABASE_URL: z.string().url(),6FRONTEND_URL: z.string().url(),7SMTP_HOST: z.string(),8SMTP_PORT: z.coerce.number(),9SMTP_USER: z.string(),10SMTP_PASSWORD:z.string(),11});1213export const serverEnv = envServerSchema.parse(process.env);1415declare global {16namespace NodeJS {17interface ProcessEnv extends z.infer<typeof envServerSchema> {}18}19}20--- app/root.tsx21export async function loader({ request }) {22const user = await getOptionalUser({ request });23return data({24user,25env: { FRONTEND_URL: serverEnv.FRONTEND_URL },26});27}2829export function useEnv() {30const data = useRouteLoaderData<typeof loader>("root");31return data?.env ?? null;32}33--- app/routes/login.tsx34const { FRONTEND_URL } = useEnv() ?? {};35console.log("URL publique :", FRONTEND_URL);
process.env
au boot : mieux vaut un crash immédiat qu’un bug
obscur en prod.serverEnv
te donne l’autocomplétion et garantit l’existence des clés.useEnv()
rend les variables publiques accessibles partout côté
client, sans context API.ProcessEnv
= fin des fautes de frappe.envServerSchema
immédiatement : tu seras alerté au prochain npm run dev
si elle manque.SMTP_HOST
, SMTP_USER
et SMTP_PASSWORD
sont utilisés
pour envoyer un courrier réel.Quelle est la principale différence entre les composants client et serveur dans React ?
Quelle technique est recommandée pour éviter les rendus inutiles dans React ?
Quel hook permet de gérer les effets de bord dans un composant React ?
Comment implémenter la gestion des erreurs pour les requêtes API dans React ?
Quelle est la meilleure pratique pour déployer une application React en production ?