Aller au contenu

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 Google 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