Découvre comment installer, configurer Prisma et modéliser ta base pour un projet e-commerce React Router. Boost ton projet avec un schéma clair et un seed rapide.
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é
Le modèle e-commerce que nous allons bâtir est loin du simple « todo ». On aura des produits, des catégories, un panier, des commandes, des factures Stripe... bref : beaucoup de relations. Prisma nous offre :
Dans cette leçon on va :
seed.ts
pour remplir 10 produits ;1npx prisma@latest init --db
eu-west-par (Paris)
– latence minimale pour tes visiteurs français.shop-router
.Le CLI ajoute deux fichiers :
1prisma/schema.prisma # schéma vide2.env # DATABASE_URL=https://…cloud.prisma.sh
La Database_URL pointe déjà vers ta base cloud PostgreSQL – pas de Docker local à configurer !
1npm install prisma @prisma/client @prisma/extension-accelerate
prisma
: CLI + générateur ;@prisma/client
: ORM typé côté serveur ;@prisma/extension-accelerate
: couche cache ✅.1import { PrismaClient } from "@prisma/client";2import { acceleratePrisma } from "@prisma/extension-accelerate";34declare global {5var prisma: ReturnType<typeof getPrisma> | undefined;6}78function getPrisma() {9return new PrismaClient().$extends(acceleratePrisma());10}1112export const prisma = globalThis.prisma ??= getPrisma();
Plutôt que tout taper à la main on part du prompt résumé ci-dessous ; copie-le dans ChatGPT/Cursor :
1// E-commerce SaaS (non multi-tenant)2// User, Category, Product (+images), Cart, Order, Invoice, EmailLog3// Stripe product & price ids, guest checkout, stock management…
L’IA génère un brouillon Prisma que tu colles dans prisma/schema.prisma
, puis relis chaque modèle :
1model Product {2id String @id @default(uuid())3name String4slug String @unique5description String?6currency String @default("EUR")7price Decimal @db.Decimal(10, 2) // ^? centimes ? voir ci-dessous8stock Int @default(0)9isActive Boolean @default(true)10stripeProductId String? @unique11stripePriceId String? @unique12images Image[]13categories Category[]14CartItem CartItem[]15createdAt DateTime @default(now())16updatedAt DateTime @updatedAt17}
Decimal
en Int
+ commentaire : « valeur en centimes ».1npx prisma migrate dev --name init-shop-router
generated/prisma
(grâce à l’option output
).export is not defined
, installe la preview feature Query Compiler dans le générateur :1generator client {2provider = "prisma-client"3output = "../generated/prisma"4previewFeatures = ["queryCompiler", "relationJoins", "driverAdapters"]5moduleFormat = "esm"6}
Regénère :
1npx prisma generate
1import { prisma } from "~/server/db.server";23const slug = (s: string) =>4s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");56async function main() {7await prisma.product.deleteMany();8await prisma.category.deleteMany();910const cats = await prisma.$transaction(11["Vêtements", "Accessoires", "Maison"].map((n) =>12prisma.category.create({ data: { name: n, slug: slug(n) } }),13),14);1516for (let i = 0; i < 10; i++) {17const name = `Produit ${i + 1}`;18await prisma.product.create({19data: {20name,21slug: `${slug(name)}-${i}`,22description: `Description de ${name}`,23price: (Math.random() * 150 + 5).toFixed(2),24stock: Math.floor(Math.random() * 100),25categories: { connect: { id: cats[i % cats.length].id } },26},27});28}29}3031main().finally(() => prisma.$disconnect());
Exécution :
1npm run dev # lance l'app dans un 1er terminal2npx tsx prisma/seed.ts
Prisma Studio (npx prisma studio
) montre tes 10 produits et 3 catégories.
1import { prisma } from "~/server/db.server";2import { useLoaderData } from "react-router";34export async function loader() {5return prisma.product.findMany({6select: { id: true, name: true, description: true, price: true },7});8}910export default function Home() {11const products = useLoaderData<typeof loader>();12return (13<main className="grid gap-6 p-8 md:grid-cols-2 lg:grid-cols-3">14{products.map((p) => (15<article key={p.id} className="rounded-lg border p-4 shadow">16<h2 className="text-lg font-semibold">{p.name}</h2>17<p className="text-sm opacity-70">{p.description}</p>18<p className="mt-2 text-right text-sky-600 font-bold">19{Number(p.price).toFixed(2)} €20</p>21</article>22))}23</main>24);25}
L’écran d’accueil affiche désormais 10 cartes produits — le back-end est prêt !
Problème | Solution |
---|---|
export is not defined au runtime | Ajoute queryCompiler + moduleFormat = "esm" dans le générateur. |
Import ancien chemin .prisma/client | Utilise toujours @prisma/client généré dans generated/prisma . |
Decimal affiché [Object object] | Convertis via Number(p.price) ou p.price.toFixed(2) côté UI. |
1git checkout -b 7-2-configuration-de-prisma2git add .3git commit -m "feat: configure Prisma + schema e-commerce + seed"4git push -u origin 7-2-configuration-de-prisma
Pull-request, merge, et ta base est officiellement dans le dépôt. 🚀
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 ?