Comment organiser proprement ton code Remix et NestJS pour un projet évolutif et maintenable.
Dans cette première étape, on va poser les bases de ton projet fullstack en structurant clairement les répertoires et en adoptant des conventions de nommage cohérentes. Cela t’évitera de te perdre en grandissant, facilitera la collaboration et la maintenabilité.
On part sur une mono-repo simple avec deux répertoires principaux :
1.2├── backend # NestJS API3└── frontend # Remix app
1.2├── backend3│ ├── src4│ │ ├── auth5│ │ ├── chat6│ │ ├── user7│ │ ├── socket8│ │ ├── stripe9│ │ └── main.ts10│ ├── test11│ └── tsconfig.json12└── frontend13├── app14│ ├── components15│ ├── hooks16│ ├── routes17│ ├── styles18│ └── utils19├── public20├── remix.config.js21└── tsconfig.json
Garde le backend/src
pour ton API NestJS et le dossier frontend/app
pour ton code Remix.
On isole la logique backend et frontend pour plus de clarté.
user-profile.ts
, chat.service.ts
MessageList.tsx
, AvatarUploader.tsx
useEnv.ts
, formatDate.ts
app/routes
en kebab-case correspondant aux URLs :
1app/routes2├── index.tsx # route "/"3├── login.tsx # route "/login"4└── chat.$chatId.tsx # route dynamique "/chat/:chatId"
app/hooks
: useOptionalUser.ts
ou useEnv.ts
app/utils
: formatDate.ts
, validateForm.ts
1import { useRouteLoaderData } from "@remix-run/react"2import { loader } from "~/root"34export const useEnv = () => {5const data = useRouteLoaderData<typeof loader>("root")6if (!data?.env) {7throw new Error("L'objet ENV n'existe pas")8}9return data.env10}
AuthModule
, UserController
, ChatService
*.dto.ts
, Entities en *.entity.ts
auth
, socket
, etc.1import { Module } from "@nestjs/common"2import { ChatService } from "./chat.service"3import { ChatController } from "./chat.controller"45@Module({6controllers: [ChatController],7providers: [ChatService],8})9export class ChatModule {}
Garde les *.dto.ts
dans un dossier dtos
ou à la racine du module.
Les entités Prisma (ou TypeORM) doivent rester dans *.entity.ts
.
1export const loader = async ({ request }: LoaderFunctionArgs) => {2const user = await getOptionalUser({ request })3const env = envSchema.parse({4WEBSOCKET_URL: process.env.WEBSOCKET_URL5?? "ws://localhost:8001",6})7return json({ user, env })8}
1import { Module } from "@nestjs/common"2import { ConfigModule } from "@nestjs/config"3import { AuthModule } from "./auth/auth.module"4import { ChatModule } from "./chat/chat.module"5import { SocketModule } from "./socket/socket.module"6import { StripeModule } from "./stripe/stripe.module"7import { UserModule } from "./user/user.module"8import { AppGateway } from "./app.gateway"910@Module({11imports: [12ConfigModule.forRoot({ isGlobal: true }),13UserModule,14AuthModule,15ChatModule,16SocketModule,17StripeModule,18],19providers: [AppGateway],20})21export class AppModule {}
Grâce à ConfigModule tu rends tes variables d’environnement globales et typées.
index.ts
pour simplifier les imports :
1export * from "./user.controller"2export * from "./user.service"
public/
pour les assets.test/
pour les specs.shared
à la racine.mkdir
et touch
.ChatService.ts
. Renomme-le selon la convention et mets-le dans le bon dossier.backend/src/auth
, crée un index.ts
qui réexporte le module, le controller et le service.Back to Démarrage du projet Remix & NestJS : structure et outils
Continue vers la suite pour installer tes dépendances et lancer ton dev server!