Modèles Vite
Modèles d'outil de build et de serveur de développement pour les projets Vite 8+. Couvre la configuration, les variables d'environnement, la configuration du proxy, le mode bibliothèque, le pré-bundling des dépendances et les pièges de production courants.
Quand l'utiliser
- Configurer
vite.config.tsouvite.config.js - Mettre en place des variables d'environnement ou des fichiers
.env - Configurer le proxy du serveur de développement pour des backends API
- Optimiser la sortie du build (chunks, minification, assets)
- Publier des bibliothèques avec
build.lib - Résoudre les problèmes de pré-bundling des dépendances ou d'interopérabilité CJS/ESM
- Déboguer les erreurs HMR, du serveur de développement ou de build
- Choisir ou ordonner les plugins Vite
Comment ça fonctionne
- Mode développement sert les fichiers sources en tant qu'ESM natif — pas de bundling. Les transformations sont effectuées à la demande pour chaque requête de module, ce qui explique pourquoi les démarrages à froid sont rapides et le HMR précis.
- Mode build utilise Rolldown (v7+) ou Rollup (v5-v6) pour empaqueter l'application pour la production avec tree-shaking, code-splitting et minification basée sur Oxc.
- Pré-bundling des dépendances convertit les dépendances CJS/UMD en ESM une fois via esbuild et met en cache le résultat sous
node_modules/.vite, ce qui évite de refaire le travail lors des démarrages suivants. - Les plugins partagent une interface unifiée entre le développement et le build — le même objet plugin fonctionne à la fois pour les transformations à la demande du serveur de développement et pour la pipeline de production.
- Les variables d'environnement sont intégrées statiquement au moment du build. Les variables préfixées par
VITE_deviennent des constantes publiques dans le bundle ; tout ce qui n'est pas préfixé est invisible pour le code client.
Exemples
Structure de configuration
Configuration de base
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
resolve: {
alias: { '@': new URL('./src', import.meta.url).pathname },
},
})
Configuration conditionnelle
// vite.config.ts
import { defineConfig, loadEnv } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig(({ command, mode }) => {
const env = loadEnv(mode, process.cwd()) // Préfixe VITE_ uniquement (sûr)
return {
plugins: [react()],
server: command === 'serve' ? { port: 3000 } : undefined,
define: {
__API_URL__: JSON.stringify(env.VITE_API_URL),
},
}
})
Options de configuration clés
| Clé | Défaut | Description |
|---|---|---|
root | '.' | Racine du projet (où se trouve index.html) |
base | '/' | Chemin de base public pour les assets déployés |
envPrefix | 'VITE_' | Préfixe pour les variables d'environnement exposées au client |
build.outDir | 'dist' | Répertoire de sortie |
build.minify | 'oxc' | Minificateur ('oxc', 'terser', ou false) |
build.sourcemap | false | true, 'inline', ou 'hidden' |
Plugins
Plugins essentiels
La plupart des besoins en plugins sont couverts par une poignée de packages bien entretenus. Utilisez-les avant d'écrire les vôtres.
| Plugin | Objectif | Quand l'utiliser |
|---|---|---|
@vitejs/plugin-react-swc | React HMR + Fast Refresh via SWC | Par défaut pour les applications React (plus rapide que la variante Babel) |
@vitejs/plugin-react | React HMR + Fast Refresh via Babel | Seulement si vous avez besoin de plugins Babel (emotion, décorateurs MobX) |
@vitejs/plugin-vue | Support Vue 3 SFC | Applications Vue |
vite-plugin-checker | Exécute tsc + ESLint dans un thread worker avec superposition HMR | Toute application TypeScript — Vite NE vérifie PAS les types pendant vite build |
vite-tsconfig-paths | Honore les alias paths de tsconfig.json | Chaque fois que vous avez déjà des alias dans tsconfig.json |
vite-plugin-dts | Émet des fichiers .d.ts en mode bibliothèque | Publication de bibliothèques TypeScript |
vite-plugin-svgr | Importe les SVG en tant que composants React | Applications React utilisant des SVG comme composants |
rollup-plugin-visualizer | Rapport de treemap/sunburst du bundle | Audits périodiques de la taille du bundle (utiliser enforce: 'post') |
vite-plugin-pwa | PWA + Workbox sans configuration | Applications fonctionnant hors ligne |
Avertissement important : vite build transpile mais NE vérifie PAS les types. Les erreurs de type sont expédiées silencieusement en production à moins d'ajouter vite-plugin-checker ou d'exécuter tsc --noEmit dans le CI.
Création de plugins personnalisés
La création est rare — la plupart des besoins sont couverts par des plugins existants. Lorsque vous en avez besoin, commencez en ligne dans vite.config.ts et extrayez-le uniquement s'il est réutilisé.
// vite.config.ts — plugin en ligne minimal
function myPlugin(): Plugin {
return {
name: 'my-plugin', // obligatoire, doit être unique
enforce: 'pre', // 'pre' | 'post' (optionnel)
apply: 'build', // 'build' | 'serve' (optionnel)
transform(code, id) {
if (!id.endsWith('.custom')) return
return { code: transformCustom(code), map: null }
},
}
}
Hooks clés : transform (modifier la source), resolveId + load (modules virtuels), transformIndexHtml (injecter dans le HTML), configureServer (ajouter un middleware de développement), hotUpdate (HMR personnalisé — remplace handleHotUpdate obsolète dans v7+).
Modules virtuels utilisent la convention de préfixe \0 — resolveId retourne '\0virtual:my-id' pour que les autres plugins l'ignorent. Le code utilisateur importe 'virtual:my-id'.
Pour l'API complète des plugins, voir vite.dev/guide/api-plugin. Utilisez vite-plugin-inspect pendant le développement pour déboguer la pipeline de transformation.
API HMR
Les plugins de framework (@vitejs/plugin-react, @vitejs/plugin-vue, etc.) gèrent le HMR automatiquement. Utilisez import.meta.hot directement uniquement lors de la création de stores d'état personnalisés, d'outils de développement ou d'utilitaires agnostiques qui doivent persister l'état entre les mises à jour.
// src/store.ts — HMR manuel pour un module vanilla
if (import.meta.hot) {
// Persister l'état entre les mises à jour (doit MUTER, ne JAMAIS réaffecter .data)
import.meta.hot.data.count = import.meta.hot.data.count ?? 0
// Nettoyer les effets de bord avant le remplacement du module
import.meta.hot.dispose((data) => clearInterval(data.intervalId))
// Accepter les propres mises à jour de ce module
import.meta.hot.accept()
}
Tout le code import.meta.hot est supprimé par tree-shaking des builds de production — aucun retrait de garde nécessaire.
Variables d'environnement
Vite charge .env, .env.local, .env.[mode] et .[mode].local dans cet ordre (le dernier écrase le précédent) ; les fichiers *.local sont ignorés par git et destinés aux secrets locaux.
Accès côté client
Seules les variables préfixées par VITE_ sont exposées au code client :
import.meta.env.VITE_API_URL // string
import.meta.env.MODE // 'development' | 'production' | personnalisé
import.meta.env.BASE_URL // valeur de config base
import.meta.env.DEV // boolean
import.meta.env.PROD // boolean
import.meta.env.SSR // boolean
Utilisation des variables d'environnement dans la configuration
// vite.config.ts
import { defineConfig, loadEnv } from 'vite'
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd()) // Préfixe VITE_ uniquement (sûr)
return {
define: {
__API_URL__: JSON.stringify(env.VITE_API_URL),
},
}
})
Sécurité
Le préfixe VITE_ n'est PAS une barrière de sécurité
Toute variable préfixée par VITE_ est intégrée statiquement dans le bundle client au moment du build. La minification, l'encodage base64 et la désactivation des sourcemaps ne la cachent PAS. Un attaquant déterminé peut extraire n'importe quelle variable VITE_ du JavaScript livré.
Règle : Seules les valeurs publiques (URLs d'API, feature flags, clés publiques) vont dans les variables VITE_. Les secrets (jetons d'API, URLs de base de données, clés privées) DOIVENT résider côté serveur derrière une API ou une fonction serverless.
Le piège de loadEnv('')
// MAUVAIS : passer '' comme troisième argument charge TOUTES les variables d'environnement — y compris les secrets serveur —
// et les rend disponibles pour être intégrées dans le code client via `define`.
const env = loadEnv(mode, process.cwd(), '')
// BON : liste de préfixes explicite
const env = loadEnv(mode, process.cwd(), ['VITE_', 'APP_'])
Source Maps en production
Les source maps en production divulguent votre code source original. Désactivez-les sauf si vous les téléchargez vers un traqueur d'erreurs (Sentry, Bugsnag) et les supprimez localement ensuite :
build: {
sourcemap: false, // par défaut — gardez-le ainsi
}
Liste de vérification .gitignore
.env.local,.env.*.local— remplacements de secrets locauxdist/— sortie du buildnode_modules/.vite— cache de pré-bundling (les entrées obsolètes provoquent des erreurs fantômes)
Proxy serveur
// vite.config.ts — server.proxy
server: {
proxy: {
'/foo': 'http://localhost:4567', // forme courte en string
'/api': {
target: 'http://localhost:8080',
changeOrigin: true, // nécessaire pour les backends à hôte virtuel
rewrite: (path) => path.replace(/^\/api/, ''),
},
},
}
Pour le proxy WebSocket, ajoutez ws: true à la configuration de la route.
Optimisation du build
Chunks manuels
// vite.config.ts — build.rolldownOptions
build: {
rolldownOptions: {
output: {
// Forme objet : grouper des packages spécifiques
manualChunks: {
'react-vendor': ['react', 'react-dom'],
'ui-vendor': ['@radix-ui/react-dialog', '@radix-ui/react-popover'],
},
},
},
}
// Forme fonction : diviser par heuristique
manualChunks(id) {
if (id.includes('node_modules/react')) return 'react-vendor'
if (id.includes('node_modules')) return 'vendor'
}
Performances
Évitez les fichiers barils
Les fichiers barils (index.ts réexportant tout depuis un répertoire) forcent Vite à charger chaque fichier réexporté même lorsque vous importez un seul symbole. C'est le ralentissement n°1 du serveur de développement signalé par la documentation officielle.
// MAUVAIS — importer un util force Vite à charger tout le baril
import { slash } from '@/utils'
// BON — import direct, un seul fichier est chargé
import { slash } from '@/utils/slash'
Soyez explicite avec les extensions d'import
Chaque extension implicite force jusqu'à 6 vérifications du système de fichiers via resolve.extensions. Dans les grandes bases de code, cela s'additionne.
// MAUVAIS
import Component from './Component'
// BON
import Component from './Component.tsx'
Réduisez allowImportingTsExtensions de tsconfig.json et resolve.extensions aux seules extensions que vous utilisez réellement.
Pré-chauffez les routes à chemin chaud
server.warmup.clientFiles pré-transforme les entrées chaudes connues avant que le navigateur ne les demande — éliminant la cascade de requêtes de chargement à froid sur les grandes applications.
// vite.config.ts
server: {
warmup: {
clientFiles: ['./src/main.tsx', './src/routes/**/*.tsx'],
},
}
Profilage des serveurs de développement lents
Quand vite dev semble lent, commencez par vite --profile, interagissez avec l'application, puis appuyez sur p+entrée pour enregistrer un fichier .cpuprofile. Chargez-le dans Speedscope pour trouver quels plugins consomment du temps — généralement les hooks buildStart, config ou configResolved dans les plugins communautaires.
Mode bibliothèque
Lors de la publication d'un package npm, utilisez build.lib. Deux pièges sont plus importants que le détail de la configuration :
- Les types ne sont pas émis — ajoutez
vite-plugin-dtsou exécuteztsc --emitDeclarationOnlyséparément. - Les dépendances de pair DOIVENT être externalisées — les pairs non listés sont empaquetés dans votre bibliothèque, provoquant des erreurs de double exécution chez les consommateurs.
// vite.config.ts
build: {
lib: {
entry: 'src/index.ts',
formats: ['es', 'cjs'],
fileName: (format) => `my-lib.${format}.js`,
},
rolldownOptions: {
external: ['react', 'react-dom', 'react/jsx-runtime'], // chaque dépendance de pair
},
}
Externalisations SSR
Les configurations nues createServer({ middlewareMode: true }) sont du ressort des auteurs de framework. La plupart des applications devraient utiliser Nuxt, Remix, SvelteKit, Astro ou TanStack Start à la place. Ce que vous modifierez en tant qu'utilisateur de framework, c'est la configuration des externalisations lorsque des dépendances cassent en SSR :
// vite.config.ts — options ssr
ssr: {
external: ['node-native-package'], // conserver en require() dans le bundle SSR
noExternal: ['esm-only-package'], // forcer l'empaquetage dans la sortie SSR (corrige la plupart des erreurs SSR)
target: 'node', // 'node' ou 'webworker'
}
Pré-bundling des dépendances
Vite pré-empaquète les dépendances pour convertir CJS/UMD en ESM et réduire le nombre de requêtes.
// vite.config.ts — optimizeDeps
optimizeDeps: {
include: [
'lodash-es', // forcer le pré-bundling des dépendances lourdes connues
'cjs-package', // dépendances CJS qui causent des problèmes d'interopérabilité
'deep-lib/components/**', // glob pour les imports profonds
],
exclude: ['local-esm-package'], // doit être un ESM valide s'il est exclu
force: true, // ignorer le cache, ré-optimiser (débogage temporaire)
}
Pièges courants
Le développement ne correspond pas au build
Le développement utilise esbuild/Rolldown pour les transformations ; le build utilise Rolldown pour l'empaquetage. Les bibliothèques CJS peuvent se comporter différemment entre les deux. Vérifiez toujours avec vite build && vite preview avant de déployer.
Chunks obsolètes après le déploiement
Les nouveaux builds produisent de nouveaux hachages de chunks. Les utilisateurs avec des sessions actives demandent d'anciens noms de fichiers qui n'existent plus. Vite n'a pas de solution intégrée. Atténuations :
- Gardez les anciens fichiers
dist/assets/actifs pendant une fenêtre de déploiement - Attrapez les erreurs d'import dynamique dans votre routeur et forcez un rechargement de page
Docker et conteneurs
Vite se lie à localhost par défaut, ce qui est inaccessible depuis l'extérieur d'un conteneur :
// vite.config.ts — configuration Docker/conteneur
server: {
host: true, // lier 0.0.0.0
hmr: { clientPort: 3000 }, // si derrière un proxy inverse
}
Accès aux fichiers dans un monorepo
Vite restreint le service de fichiers à la racine du projet. Les packages en dehors de la racine sont bloqués :
// vite.config.ts — accès aux fichiers dans un monorepo
server: {
fs: {
allow: ['..'], // autoriser le répertoire parent (racine de l'espace de travail)
},
}
Anti-patrons
// MAUVAIS : Définir envPrefix à '' expose TOUTES les variables d'environnement (y compris les secrets) au client
envPrefix: ''
// MAUVAIS : Supposer que require() fonctionne en ESM — utilisez import à la place
Débogage
Erreurs de build
# Afficher la sortie détaillée du build
vite build --debug
# Vérifier les fichiers résolus et les transformations appliquées
npx vite-plugin-inspect
Problèmes de pré-bundling
# Effacer le cache de pré-bundling et forcer la ré-optimisation
rm -rf node_modules/.vite
vite --force
Vérification des versions
npx vite --version # Vite CLI
node -e "console.log(require('vite/package.json').version)" # Version du package