Frameworks courants¶
L'écosystème JavaScript et TypeScript est le plus vaste de tous les langages, avec des frameworks couvrant le frontend, le backend et le full-stack. Ce chapitre présente les options majeures avec leurs forces, leurs cas d'usage et des exemples de démarrage minimaux.
Frameworks frontend¶
| Framework | Auteur | Paradigme | Taille bundle (min+gz) | Points forts |
|---|---|---|---|---|
| React | Meta | UI library | ~45 KB | Écosystème, emploi, flexibilite |
| Vue 3 | Evan You | Progressive MVC | ~35 KB | Courbe d'apprentissage, Composition API |
| Angular | Full framework | ~150 KB | Enterprise, DI, opinionated | |
| Svelte | Rich Harris | Compile-time | ~10 KB | Performances, zero virtual DOM |
| Solid | Ryan Carniato | Reactive signals | ~7 KB | Performances maximales, fine-grained reactivity |
React 19¶
React reste le choix dominant sur le marche de l'emploi. React 19 introduit les Server Components stable et les Actions.
// components/ItemList.tsx — React 19 avec hooks modernes
import { useState, useEffect } from 'react';
interface Item {
id: number;
name: string;
done: boolean;
}
export default function ItemList() {
const [items, setItems] = useState<Item[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('/api/items')
.then((res) => res.json())
.then((data: Item[]) => {
setItems(data);
setLoading(false);
});
}, []);
if (loading) return <p>Chargement...</p>;
return (
<ul>
{items.map((item) => (
<li key={item.id} style={{ textDecoration: item.done ? 'line-through' : 'none' }}>
{item.name}
</li>
))}
</ul>
);
}
Vue 3 — Composition API¶
<!-- ItemList.vue — Vue 3 avec <script setup> et TypeScript -->
<script setup lang="ts">
import { ref, onMounted } from 'vue';
interface Item {
id: number;
name: string;
done: boolean;
}
const items = ref<Item[]>([]);
const loading = ref(true);
onMounted(async () => {
const res = await fetch('/api/items');
items.value = await res.json();
loading.value = false;
});
</script>
<template>
<p v-if="loading">Chargement...</p>
<ul v-else>
<li
v-for="item in items"
:key="item.id"
:style="{ textDecoration: item.done ? 'line-through' : 'none' }"
>
{{ item.name }}
</li>
</ul>
</template>
Svelte 5¶
<!-- ItemList.svelte — Svelte 5 avec runes -->
<script lang="ts">
interface Item {
id: number;
name: string;
done: boolean;
}
let items = $state<Item[]>([]);
let loading = $state(true);
$effect(() => {
fetch('/api/items')
.then((r) => r.json())
.then((data: Item[]) => {
items = data;
loading = false;
});
});
</script>
{#if loading}
<p>Chargement...</p>
{:else}
<ul>
{#each items as item (item.id)}
<li style:text-decoration={item.done ? 'line-through' : 'none'}>
{item.name}
</li>
{/each}
</ul>
{/if}
Frameworks backend¶
| Framework | Base | Style | Performance | Points forts |
|---|---|---|---|---|
| Express | Node.js | Minimaliste | Moyenne | Écosystème immense, documentation abondante |
| Fastify | Node.js | Schéma-first | Élevée | JSON Schéma, plugins, TypeScript natif |
| Nest.js | Express/Fastify | Decorateurs | Moyenne | Angular-like, DI, enterprise, modules |
| Hono | WinterCG | Edge-first | Très élevée | Multi-runtime, ultralegere, Web Standards |
| Elysia | Bun | Type-safe DSL | Maximale | Bun-native, end-to-end types avec Eden |
Fastify — démarrage minimal¶
// src/server.ts — Fastify 5 avec TypeScript
import Fastify from 'fastify';
import { Type } from '@sinclair/typebox';
const app = Fastify({ logger: true });
// Schema JSON Schema via TypeBox
const ItemSchema = Type.Object({
id: Type.Number(),
name: Type.String(),
done: Type.Boolean(),
});
// Route GET avec schema de reponse valide
app.get('/items', {
schema: {
response: {
200: Type.Array(ItemSchema),
},
},
handler: async (_req, _reply) => {
return [{ id: 1, name: 'Premier item', done: false }];
},
});
await app.listen({ port: 3000 });
// Acces : http://localhost:3000/items
Hono — démarrage minimal (multi-runtime)¶
// src/index.ts — Hono fonctionne sur Node.js, Deno, Bun, Cloudflare Workers
import { Hono } from 'hono';
import { zValidator } from '@hono/zod-validator';
import { z } from 'zod';
const app = new Hono();
const itemSchema = z.object({
name: z.string().min(1),
done: z.boolean().default(false),
});
app.get('/items', (c) => {
return c.json([{ id: 1, name: 'Premier item', done: false }]);
});
app.post('/items', zValidator('json', itemSchema), (c) => {
const body = c.req.valid('json');
return c.json({ id: 2, ...body }, 201);
});
export default app; // compatible Cloudflare Workers, Deno Deploy, Bun
Meta-frameworks full-stack¶
Les meta-frameworks combinent frontend et backend dans une seule application, avec rendu hybride (SSR, SSG, ISR).
| Meta-framework | Base | Runtime | Rendu | Points forts |
|---|---|---|---|---|
| Next.js | React | Node.js | SSR, SSG, ISR, RSC | Écosystème, Vercel, App Router |
| Nuxt 3 | Vue 3 | Node.js | SSR, SSG, hybrid | Auto-imports, Nitro, excellent DX |
| SvelteKit | Svelte | Node.js/Edge | SSR, SSG, hybrid | Performances, adapters, forme du serveur |
| Astro 5 | Multi | Node.js/Edge | SSG, SSR, Islands | Zero JS par défaut, multi-framework |
| Remix | React | Node.js/Edge | SSR | Nested routes, loaders/actions, progressif |
Next.js 15 — App Router¶
// app/items/page.tsx — Next.js 15 Server Component (par defaut)
import { Suspense } from 'react';
interface Item {
id: number;
name: string;
done: boolean;
}
// Composant serveur : fetch direct sans useEffect
async function ItemList() {
// fetch natif avec cache Next.js
const res = await fetch('http://localhost:3000/api/items', {
next: { revalidate: 60 }, // ISR : revalide toutes les 60 secondes
});
const items: Item[] = await res.json();
return (
<ul>
{items.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}
// Page principale avec Suspense pour le streaming
export default function ItemsPage() {
return (
<main>
<h1>Liste des items</h1>
<Suspense fallback={<p>Chargement...</p>}>
<ItemList />
</Suspense>
</main>
);
}
Écosystème complementaire¶
Ces bibliotheques sont devenues des standards de facto independamment du framework choisi.
Prisma — ORM TypeScript-first¶
// prisma/schema.prisma
// generator client {
// provider = "prisma-client-js"
// }
// datasource db {
// provider = "sqlite"
// url = "file:./dev.db"
// }
// model Item {
// id Int @id @default(autoincrement())
// name String
// done Boolean @default(false)
// }
// src/db.ts — Client Prisma singleton
import { PrismaClient } from '@prisma/client';
const globalForPrisma = globalThis as unknown as { prisma: PrismaClient };
export const prisma =
globalForPrisma.prisma ?? new PrismaClient({ log: ['query'] });
if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma;
Zod — Validation et schémas runtime¶
// src/schemas.ts — Zod 3.x pour validation et inference de types
import { z } from 'zod';
// Schema de creation
export const CreateItemSchema = z.object({
name: z.string().min(1, 'Le nom est requis').max(100),
done: z.boolean().optional().default(false),
});
// Schema de mise a jour — tous les champs optionnels
export const UpdateItemSchema = CreateItemSchema.partial();
// Types inferres automatiquement depuis les schemas
export type CreateItemInput = z.infer<typeof CreateItemSchema>;
export type UpdateItemInput = z.infer<typeof UpdateItemSchema>;
tRPC — API typee end-to-end¶
// server/router.ts — tRPC 11 avec Zod
import { initTRPC } from '@trpc/server';
import { z } from 'zod';
const t = initTRPC.create();
export const appRouter = t.router({
items: t.router({
list: t.procedure.query(async () => {
// retourne la liste des items
return [{ id: 1, name: 'Item', done: false }];
}),
create: t.procedure
.input(z.object({ name: z.string().min(1) }))
.mutation(async ({ input }) => {
// input est type-safe : { name: string }
return { id: 2, name: input.name, done: false };
}),
}),
});
export type AppRouter = typeof appRouter;
// Le client infer les types depuis AppRouter sans generation de code
Auth.js (NextAuth) — Authentification¶
// app/api/auth/[...nextauth]/route.ts — Auth.js 5 avec Next.js
import NextAuth from 'next-auth';
import GitHub from 'next-auth/providers/github';
import { PrismaAdapter } from '@auth/prisma-adapter';
import { prisma } from '@/lib/db';
export const { handlers, signIn, signOut, auth } = NextAuth({
adapter: PrismaAdapter(prisma),
providers: [
GitHub({
clientId: process.env.GITHUB_ID!,
clientSecret: process.env.GITHUB_SECRET!,
}),
],
callbacks: {
session({ session, user }) {
session.user.id = user.id;
return session;
},
},
});
export const { GET, POST } = handlers;
Choix par contexte
- Startup / prototype : Next.js + Prisma + Auth.js + Zod — écosystème unifie
- API standalone haute performance : Fastify ou Hono
- Enterprise / grande équipe : Nest.js avec architecture modulaire
- Edge / CDN : Hono ou Astro avec adapters Cloudflare/Vercel
- Contenu statique : Astro — zero JS par défaut, excellent SEO