Vite 6 + React + TypeScript : créer une application web moderne de A à Z en 2026

Vite 6 redéfinit le développement frontend. Avec sa nouvelle Environment API, un HMR encore plus rapide et un écosystème de plugins mature, Vite 6 est devenu le standard de facto pour les projets React + TypeScript en 2026. Dans ce guide, vous construirez une application complète en exploitant chaque fonctionnalité clé de Vite 6.
Ce que vous apprendrez
À la fin de ce guide, vous saurez :
- Créer et configurer un projet Vite 6 + React + TypeScript de zéro
- Comprendre et utiliser la nouvelle Environment API de Vite 6
- Configurer le Hot Module Replacement (HMR) pour un développement ultra-rapide
- Optimiser le bundling de production avec le tree-shaking et le code splitting
- Écrire et exécuter des tests avec Vitest
- Configurer les variables d'environnement et les proxies API
- Ajouter du CSS moderne avec CSS Modules et PostCSS
- Déployer votre application en production
Prérequis
Avant de commencer, assurez-vous d'avoir :
- Node.js 20+ installé (ou Bun 1.1+)
- Des connaissances de base en React (composants, hooks, JSX)
- Une familiarité avec TypeScript (types, interfaces, génériques)
- Un éditeur de code — VS Code ou Cursor recommandé
- Un terminal avec accès à npm ou pnpm
Pourquoi Vite 6 ?
Depuis sa première version en 2020, Vite a révolutionné le développement frontend en remplaçant les bundlers lourds comme webpack par un serveur de développement basé sur les modules ES natifs. Vite 6, sorti fin 2025, apporte des améliorations majeures :
| Fonctionnalité | Vite 5 | Vite 6 |
|---|---|---|
| Environment API | Absente | Complète et stable |
| Serveur de dev | Rapide | Encore plus rapide |
| Support de Rolldown | Expérimental | Stable |
| Résolution des modules | Standard | Optimisée |
| Configuration TypeScript | Bonne | Excellente avec autocomplétion |
La principale nouveauté de Vite 6 est l'Environment API — une abstraction qui permet de gérer plusieurs environnements d'exécution (client, SSR, worklets) dans un même projet avec des configurations distinctes.
Étape 1 : Créer le projet
Commençons par scaffolder un nouveau projet avec le template React + TypeScript officiel de Vite :
npm create vite@latest mon-app-vite -- --template react-ts
cd mon-app-vite
npm installSi vous préférez pnpm (recommandé pour les performances) :
pnpm create vite mon-app-vite --template react-ts
cd mon-app-vite
pnpm installStructure du projet
Voici la structure générée :
mon-app-vite/
├── public/
│ └── vite.svg
├── src/
│ ├── assets/
│ │ └── react.svg
│ ├── App.css
│ ├── App.tsx
│ ├── index.css
│ ├── main.tsx
│ └── vite-env.d.ts
├── index.html
├── package.json
├── tsconfig.json
├── tsconfig.app.json
├── tsconfig.node.json
└── vite.config.ts
Contrairement aux bundlers traditionnels, index.html est à la racine du projet — Vite l'utilise comme point d'entrée plutôt qu'un fichier JavaScript.
Lancez le serveur de développement :
npm run devOuvrez http://localhost:5173 — vous verrez l'application React par défaut avec le HMR activé. Modifiez src/App.tsx et observez les changements instantanés dans le navigateur.
Étape 2 : Comprendre la configuration Vite 6
Ouvrez vite.config.ts — le cœur de votre configuration :
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
})Configuration avancée
Enrichissons cette configuration pour un projet de production :
import { defineConfig, loadEnv } from 'vite'
import react from '@vitejs/plugin-react'
import { resolve } from 'path'
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd(), '')
return {
plugins: [react()],
// Alias de chemins pour des imports propres
resolve: {
alias: {
'@': resolve(__dirname, './src'),
'@components': resolve(__dirname, './src/components'),
'@hooks': resolve(__dirname, './src/hooks'),
'@utils': resolve(__dirname, './src/utils'),
'@types': resolve(__dirname, './src/types'),
},
},
// Configuration du serveur de développement
server: {
port: 3000,
open: true,
// Proxy pour les appels API en développement
proxy: {
'/api': {
target: env.VITE_API_URL || 'http://localhost:8080',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
},
},
// Configuration du build de production
build: {
target: 'es2022',
sourcemap: true,
rollupOptions: {
output: {
manualChunks: {
vendor: ['react', 'react-dom'],
},
},
},
},
// Configuration CSS
css: {
modules: {
localsConvention: 'camelCase',
},
},
}
})Configurer les alias TypeScript
Pour que TypeScript reconnaisse les alias @, mettez à jour tsconfig.app.json :
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@components/*": ["./src/components/*"],
"@hooks/*": ["./src/hooks/*"],
"@utils/*": ["./src/utils/*"],
"@types/*": ["./src/types/*"]
}
}
}Étape 3 : L'Environment API de Vite 6
La fonctionnalité phare de Vite 6 est l'Environment API. Avant Vite 6, le serveur de développement traitait tout le code dans un seul pipeline. Désormais, chaque environnement (client, SSR, worker) a sa propre configuration et son propre module graph.
Pourquoi c'est important
Imaginons un projet avec du rendu côté serveur (SSR). Avant Vite 6, le même pipeline transformait le code client et le code serveur, ce qui pouvait causer des conflits. Avec l'Environment API :
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
environments: {
// Environnement client (navigateur)
client: {
build: {
outDir: 'dist/client',
rollupOptions: {
input: './index.html',
},
},
},
// Environnement SSR (Node.js)
ssr: {
build: {
outDir: 'dist/server',
ssr: true,
},
resolve: {
conditions: ['node'],
},
},
},
})Utilisation dans les plugins
Si vous développez des plugins Vite, l'Environment API vous permet de cibler un environnement spécifique :
function monPluginVite() {
return {
name: 'mon-plugin',
// Ce hook s'exécute dans chaque environnement
resolveId(source, importer, options) {
if (this.environment.name === 'ssr') {
// Logique spécifique au SSR
return null
}
// Logique par défaut (client)
return null
},
// Configurer différemment selon l'environnement
configureServer(server) {
const clientEnv = server.environments.client
const ssrEnv = server.environments.ssr
// Chaque environnement a son propre module graph
console.log('Modules client:', clientEnv.moduleGraph.idToModuleMap.size)
},
}
}Pour la plupart des projets React classiques (SPA sans SSR), l'Environment API fonctionne automatiquement avec l'environnement client par défaut. Son intérêt principal se manifeste dans les frameworks full-stack comme Next.js, Remix ou Astro qui utilisent Vite en interne.
Étape 4 : Structurer le projet React
Créons une architecture de projet scalable :
mkdir -p src/{components,hooks,utils,types,pages,styles,services}Layout principal
Créez src/components/Layout.tsx :
import { Outlet } from 'react-router-dom'
import { Header } from './Header'
import { Footer } from './Footer'
import styles from './Layout.module.css'
export function Layout() {
return (
<div className={styles.layout}>
<Header />
<main className={styles.main}>
<Outlet />
</main>
<Footer />
</div>
)
}CSS Modules avec Vite
Créez src/components/Layout.module.css — Vite supporte les CSS Modules nativement :
.layout {
min-height: 100vh;
display: flex;
flex-direction: column;
}
.main {
flex: 1;
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
width: 100%;
}Composant Header
Créez src/components/Header.tsx :
import { Link, NavLink } from 'react-router-dom'
import styles from './Header.module.css'
const navLinks = [
{ to: '/', label: 'Accueil' },
{ to: '/about', label: 'À propos' },
{ to: '/dashboard', label: 'Tableau de bord' },
]
export function Header() {
return (
<header className={styles.header}>
<Link to="/" className={styles.logo}>
Mon App Vite
</Link>
<nav className={styles.nav}>
{navLinks.map(({ to, label }) => (
<NavLink
key={to}
to={to}
className={({ isActive }) =>
isActive ? styles.active : styles.link
}
>
{label}
</NavLink>
))}
</nav>
</header>
)
}Composant Footer
Créez src/components/Footer.tsx :
import styles from './Footer.module.css'
export function Footer() {
return (
<footer className={styles.footer}>
<p>
Construit avec Vite 6 + React + TypeScript —{' '}
{new Date().getFullYear()}
</p>
</footer>
)
}Étape 5 : Routing avec React Router
Installez React Router :
npm install react-router-domCréez src/pages/Home.tsx :
import styles from './Home.module.css'
export function Home() {
return (
<div className={styles.home}>
<h1>Bienvenue sur Mon App Vite 6</h1>
<p>
Cette application est construite avec Vite 6, React 19 et TypeScript
pour des performances optimales.
</p>
<div className={styles.features}>
<FeatureCard
title="HMR Ultra-rapide"
description="Modifications reflétées instantanément dans le navigateur"
/>
<FeatureCard
title="TypeScript Natif"
description="Support TypeScript complet sans configuration"
/>
<FeatureCard
title="Build Optimisé"
description="Tree-shaking et code splitting automatiques"
/>
</div>
</div>
)
}
function FeatureCard({ title, description }: { title: string; description: string }) {
return (
<div className={styles.card}>
<h3>{title}</h3>
<p>{description}</p>
</div>
)
}Mettez à jour src/main.tsx pour configurer le routing :
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import { createBrowserRouter, RouterProvider } from 'react-router-dom'
import { Layout } from '@/components/Layout'
import { Home } from '@/pages/Home'
import './index.css'
const router = createBrowserRouter([
{
element: <Layout />,
children: [
{ index: true, element: <Home /> },
{
path: 'about',
lazy: () => import('@/pages/About').then(m => ({ Component: m.About })),
},
{
path: 'dashboard',
lazy: () => import('@/pages/Dashboard').then(m => ({ Component: m.Dashboard })),
},
],
},
])
createRoot(document.getElementById('root')!).render(
<StrictMode>
<RouterProvider router={router} />
</StrictMode>,
)Remarquez l'utilisation de lazy() pour le code splitting — les pages About et Dashboard seront chargées à la demande, réduisant la taille du bundle initial.
Étape 6 : Variables d'environnement
Vite 6 gère les variables d'environnement avec des fichiers .env :
# .env — chargé dans tous les modes
VITE_APP_TITLE=Mon App Vite
VITE_API_URL=https://api.exemple.com
# .env.development — seulement en mode dev
VITE_API_URL=http://localhost:8080
VITE_DEBUG=true
# .env.production — seulement en mode production
VITE_API_URL=https://api.production.comImportant : seules les variables préfixées par VITE_ sont exposées au code client. Les variables sans ce préfixe restent côté serveur pour protéger les secrets.
Typage des variables d'environnement
Créez src/env.d.ts pour le typage TypeScript :
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_APP_TITLE: string
readonly VITE_API_URL: string
readonly VITE_DEBUG?: string
}
interface ImportMeta {
readonly env: ImportMetaEnv
}Utilisation dans votre code :
const apiUrl = import.meta.env.VITE_API_URL
const appTitle = import.meta.env.VITE_APP_TITLE
const isDev = import.meta.env.DEV // boolean automatiqueÉtape 7 : Fetching de données avec un hook personnalisé
Créez un hook réutilisable pour les appels API. Créez src/hooks/useFetch.ts :
import { useState, useEffect } from 'react'
interface FetchState<T> {
data: T | null
loading: boolean
error: string | null
}
export function useFetch<T>(url: string): FetchState<T> {
const [state, setState] = useState<FetchState<T>>({
data: null,
loading: true,
error: null,
})
useEffect(() => {
const controller = new AbortController()
async function fetchData() {
try {
setState(prev => ({ ...prev, loading: true, error: null }))
const response = await fetch(url, { signal: controller.signal })
if (!response.ok) {
throw new Error(`Erreur HTTP : ${response.status}`)
}
const data = await response.json()
setState({ data, loading: false, error: null })
} catch (err) {
if (err instanceof DOMException && err.name === 'AbortError') return
setState({
data: null,
loading: false,
error: err instanceof Error ? err.message : 'Erreur inconnue',
})
}
}
fetchData()
return () => controller.abort()
}, [url])
return state
}Page Dashboard avec données dynamiques
Créez src/pages/Dashboard.tsx :
import { useFetch } from '@/hooks/useFetch'
import styles from './Dashboard.module.css'
interface User {
id: number
name: string
email: string
}
export function Dashboard() {
const { data: users, loading, error } = useFetch<User[]>(
'https://jsonplaceholder.typicode.com/users'
)
if (loading) return <div className={styles.loading}>Chargement...</div>
if (error) return <div className={styles.error}>Erreur : {error}</div>
return (
<div className={styles.dashboard}>
<h1>Tableau de bord</h1>
<div className={styles.grid}>
{users?.map(user => (
<div key={user.id} className={styles.userCard}>
<h3>{user.name}</h3>
<p>{user.email}</p>
</div>
))}
</div>
</div>
)
}Étape 8 : Optimisation du build de production
Vite 6 utilise Rollup (ou bientôt Rolldown) pour le build de production. Configurons les optimisations :
Code splitting avancé
// vite.config.ts
export default defineConfig({
build: {
target: 'es2022',
minify: 'esbuild',
sourcemap: true,
rollupOptions: {
output: {
manualChunks(id) {
// Séparer les dépendances React dans un chunk vendor
if (id.includes('node_modules/react')) {
return 'react-vendor'
}
// Séparer React Router
if (id.includes('node_modules/react-router')) {
return 'router'
}
// Regrouper les autres dépendances
if (id.includes('node_modules')) {
return 'vendor'
}
},
},
},
// Seuil d'avertissement pour les chunks
chunkSizeWarningLimit: 500,
},
})Analyser la taille du bundle
Installez le plugin d'analyse :
npm install -D rollup-plugin-visualizerAjoutez-le à votre configuration :
import { visualizer } from 'rollup-plugin-visualizer'
export default defineConfig({
plugins: [
react(),
visualizer({
open: true,
gzipSize: true,
brotliSize: true,
}),
],
})Lancez le build :
npm run buildUn rapport interactif s'ouvrira dans votre navigateur, montrant la taille de chaque module et chunk.
Préchargement des assets
Vite 6 génère automatiquement les balises <link rel="modulepreload"> pour les chunks critiques. Vous pouvez aussi configurer le preload manuellement :
export default defineConfig({
build: {
modulePreload: {
polyfill: true, // Polyfill pour les anciens navigateurs
},
},
})Étape 9 : Tests avec Vitest
Vitest est le framework de test naturel pour Vite — il partage la même configuration et offre une compatibilité API avec Jest.
Installation
npm install -D vitest @testing-library/react @testing-library/jest-dom jsdomConfiguration
Ajoutez la configuration Vitest dans vite.config.ts :
/// <reference types="vitest/config" />
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
test: {
globals: true,
environment: 'jsdom',
setupFiles: './src/test/setup.ts',
include: ['src/**/*.{test,spec}.{ts,tsx}'],
coverage: {
provider: 'v8',
reporter: ['text', 'json', 'html'],
include: ['src/**/*.{ts,tsx}'],
exclude: ['src/**/*.test.{ts,tsx}', 'src/test/**'],
},
},
})Créez src/test/setup.ts :
import '@testing-library/jest-dom'Écrire un test
Créez src/hooks/useFetch.test.ts :
import { renderHook, waitFor } from '@testing-library/react'
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { useFetch } from './useFetch'
describe('useFetch', () => {
beforeEach(() => {
vi.restoreAllMocks()
})
it('devrait retourner les données après un fetch réussi', async () => {
const mockData = [{ id: 1, name: 'Test' }]
global.fetch = vi.fn().mockResolvedValue({
ok: true,
json: () => Promise.resolve(mockData),
})
const { result } = renderHook(() =>
useFetch('https://api.exemple.com/data')
)
expect(result.current.loading).toBe(true)
await waitFor(() => {
expect(result.current.loading).toBe(false)
expect(result.current.data).toEqual(mockData)
expect(result.current.error).toBeNull()
})
})
it("devrait gérer les erreurs HTTP", async () => {
global.fetch = vi.fn().mockResolvedValue({
ok: false,
status: 404,
})
const { result } = renderHook(() =>
useFetch('https://api.exemple.com/not-found')
)
await waitFor(() => {
expect(result.current.loading).toBe(false)
expect(result.current.error).toBe('Erreur HTTP : 404')
expect(result.current.data).toBeNull()
})
})
})Tester un composant
Créez src/components/Header.test.tsx :
import { render, screen } from '@testing-library/react'
import { MemoryRouter } from 'react-router-dom'
import { describe, it, expect } from 'vitest'
import { Header } from './Header'
describe('Header', () => {
it('devrait afficher le logo et les liens de navigation', () => {
render(
<MemoryRouter>
<Header />
</MemoryRouter>
)
expect(screen.getByText('Mon App Vite')).toBeInTheDocument()
expect(screen.getByText('Accueil')).toBeInTheDocument()
expect(screen.getByText('À propos')).toBeInTheDocument()
expect(screen.getByText('Tableau de bord')).toBeInTheDocument()
})
})Lancez les tests :
npx vitest # Mode watch
npx vitest run # Exécution unique
npx vitest --coverage # Avec couvertureÉtape 10 : Plugins Vite essentiels
Plugin SVG en composants React
npm install -D vite-plugin-svgrimport svgr from 'vite-plugin-svgr'
export default defineConfig({
plugins: [
react(),
svgr(),
],
})Utilisez des SVG comme composants :
import { ReactComponent as Logo } from '@/assets/logo.svg'
function App() {
return <Logo className="logo" />
}Plugin de compression
npm install -D vite-plugin-compressionimport compression from 'vite-plugin-compression'
export default defineConfig({
plugins: [
react(),
compression({
algorithm: 'brotliCompress',
ext: '.br',
}),
compression({
algorithm: 'gzip',
ext: '.gz',
}),
],
})Plugin PWA
npm install -D vite-plugin-pwaimport { VitePWA } from 'vite-plugin-pwa'
export default defineConfig({
plugins: [
react(),
VitePWA({
registerType: 'autoUpdate',
manifest: {
name: 'Mon App Vite',
short_name: 'MonApp',
theme_color: '#646cff',
},
}),
],
})Étape 11 : Déploiement en production
Build de production
npm run buildVite génère les fichiers optimisés dans le dossier dist/ :
dist/
├── assets/
│ ├── index-[hash].js # Code de l'application
│ ├── react-vendor-[hash].js # Chunk React
│ ├── vendor-[hash].js # Autres dépendances
│ └── index-[hash].css # Styles
├── index.html
└── vite.svg
Prévisualiser le build
npm run previewCela lance un serveur local servant les fichiers de production — parfait pour vérifier que tout fonctionne avant le déploiement.
Déployer sur Vercel
npm install -g vercel
vercelVercel détecte automatiquement Vite et configure le build.
Déployer sur Cloudflare Pages
npm install -D wrangler
npx wrangler pages deploy distDéployer sur un VPS avec Nginx
Créez un fichier nginx.conf :
server {
listen 80;
server_name monapp.com;
root /var/www/mon-app-vite/dist;
index index.html;
# Compression gzip
gzip on;
gzip_types text/css application/javascript application/json image/svg+xml;
# Cache des assets statiques (fichiers hashés)
location /assets/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# SPA fallback
location / {
try_files $uri $uri/ /index.html;
}
}Le hashing automatique des noms de fichiers par Vite permet un cache agressif — les fichiers changent de nom à chaque modification, donc les utilisateurs obtiennent toujours la dernière version.
Dépannage
Le HMR ne fonctionne pas
Si les modifications ne se reflètent pas automatiquement :
- Vérifiez que votre fichier exporte un composant React (le HMR de React nécessite des exports de composants)
- Vérifiez la console du navigateur pour les erreurs WebSocket
- Essayez de redémarrer le serveur de dev :
npm run dev
Erreur "Failed to resolve import"
Cela signifie généralement un alias mal configuré :
- Vérifiez que l'alias est défini dans
vite.config.tsETtsconfig.app.json - Redémarrez le serveur de dev après avoir modifié la configuration
- Vérifiez que le chemin du fichier importé existe
Build trop volumineux
- Utilisez
rollup-plugin-visualizerpour identifier les gros modules - Implémentez le code splitting avec
React.lazy()ou le routing lazy - Vérifiez que le tree-shaking fonctionne — utilisez des imports nommés au lieu des imports par défaut depuis les grandes bibliothèques
Prochaines étapes
Maintenant que vous maîtrisez Vite 6 avec React et TypeScript, voici quelques pistes pour aller plus loin :
- State management — intégrez Zustand ou Jotai pour la gestion d'état
- UI Components — ajoutez shadcn/ui pour une bibliothèque de composants accessible
- Backend — connectez votre app à une API avec tRPC ou TanStack Query
- Tests E2E — configurez Playwright pour les tests end-to-end
- CI/CD — mettez en place un pipeline GitHub Actions pour automatiser les tests et le déploiement
Conclusion
Vite 6 représente une étape majeure dans l'évolution du tooling frontend JavaScript. Avec la nouvelle Environment API, des performances de développement encore améliorées et un écosystème de plugins riche, il offre tout ce dont vous avez besoin pour construire des applications React + TypeScript modernes et performantes.
Les points clés à retenir :
- Vite 6 est rapide — le HMR instantané et le build optimisé accélèrent votre workflow
- L'Environment API ouvre de nouvelles possibilités pour le SSR et les frameworks full-stack
- Vitest s'intègre naturellement et offre une expérience de test de premier ordre
- L'écosystème de plugins couvre tous les besoins : PWA, SVG, compression, analyse
Que vous démarriez un nouveau projet ou que vous migriez depuis webpack ou Create React App, Vite 6 est le choix évident pour le développement frontend en 2026.
Discutez de votre projet avec nous
Nous sommes ici pour vous aider avec vos besoins en développement Web. Planifiez un appel pour discuter de votre projet et comment nous pouvons vous aider.
Trouvons les meilleures solutions pour vos besoins.
Articles connexes

Guide complet de Bun 2.0 : le runtime JavaScript tout-en-un pour 2026
Maîtrisez Bun 2.0 de zéro — le runtime JavaScript ultra-rapide qui remplace Node.js, npm, webpack et Jest en un seul binaire. Ce guide pratique couvre le runtime, le gestionnaire de paquets, le bundler, le test runner et la construction d'une API REST de production.

Construire une application full-stack avec TanStack Start : le framework React nouvelle génération
Apprenez à créer une application full-stack complète avec TanStack Start, le meta-framework React propulsé par TanStack Router et Vite. Ce tutoriel couvre le routage fichier, les fonctions serveur, le middleware, l'authentification et le déploiement.

Construire des applications collaboratives Local-First avec Yjs et React
Apprenez à construire des applications collaboratives en temps réel fonctionnant hors ligne avec les CRDTs Yjs et React. Ce tutoriel couvre la synchronisation sans conflits, l'architecture offline-first et la création d'un éditeur de documents partagé.