Blog

Guide de Migration : Passer de Webpack à Vite.js

Basculez votre projet buildé sous Webpack sur Vite.js en toute sécurité. Guide étape par étape.

Mathieu Ducrot Mathieu Ducrot
|
|
9 min de lecture
| Tech
Résumez cette page avec votre IA préférée :
Migration Webpack vers Vite.js : Booster vos temps de build front

Webpack a longtemps été l’outil de référence pour le bundling des applications JavaScript. Robuste, universel, mais progressivement distancé par une nouvelle génération d’outils plus rapides.

Vite, créé par Evan You (le créateur de Vue.js), change radicalement la donne en s’appuyant sur les modules ES natifs du navigateur (ainsi que Rolldown depuis la récente version 8). Le résultat : des démarrages à froid quasi instantanés et des builds de production significativement plus rapides.

Chez SmartBooster, nous avons réalisé cette migration sur un projet Vue 3 en production : une application de formulaires multi-étapes complexes avec une architecture multi-entrées (SPA + web component).

Voici le retour d’expérience complet, avec les pièges à éviter et les solutions que nous avons mis en place.


Sommaire

  1. Pourquoi migrer vers Vite ?
  2. Planifier la migration avec l’aide de l’IA
  3. Mise en place de la configuration Vite
  4. Migration des variables d’environnement
  5. Remplacement des imports dynamiques Webpack
  6. Les erreurs que nous avons rencontrées (et leurs solutions)
  7. Résultats et bilan

1. Pourquoi migrer vers Vite ?

Les raisons de quitter Webpack pour Vite sont aujourd’hui nombreuses et mesurables.

Performances de build

Sur notre projet, le build de production est passé d’environ 1 minute en moyenne à 15 secondes, soit un gain d’un facteur 4. Cette amélioration s’explique par Rolldown, le bundler Rust qui remplace Rollup dans Vite 8, capable de paralléliser massivement les opérations de transformation et de bundling.

En développement, le gain est encore plus sensible : là où Webpack recompilait l’intégralité du bundle à chaque démarrage, Vite sert les modules ES directement depuis leur source via le navigateur. Le cold start passe de plusieurs dizaines de secondes à moins d’une seconde.

Une configuration nettement plus simple

La configuration Webpack d’un projet Vue CLI accumulait facilement une dizaine de loaders (vue-loader, babel-loader, css-loader, sass-loader, style-loader…), des plugins, des résolutions d’alias, et une gestion des modes de build ad hoc. Vite remplace tout cela par un fichier vite.config.js concis, avec une prise en charge native du SCSS, des assets statiques, et des alias de chemin.

Un écosystème en pleine santé

Vue CLI est en maintenance passive depuis 2022. Vite est devenu le standard de facto pour les projets Vue, React et Svelte. Rester sur Webpack/vue-cli-service, c’est accumuler de la dette technique sur un outillage qui ne reçoit plus de mises à jour significatives.


2. Planifier la migration avec l’aide de l’IA

Ce type de migration implique de nombreuses décisions : gestion des modes d’environnement, remplacement des patterns Webpack-spécifiques, compatibilité des dépendances, choix des versions cibles. Avant d’écrire la moindre ligne de configuration, nous avons utilisé Claude (modèle Opus) via Claude Code pour analyser l’ensemble de la codebase et produire un plan de migration structuré.

L’analyse a couvert les fichiers de configuration existants (vue.config.js, babel.config.js, jest.config.js), les patterns d’import dans les composants Vue, les variables d’environnement, et les dépendances à remplacer ou retirer.

Pour compléter cette analyse avec la documentation la plus à jour de Vite 8, nous avons utilisé le MCP Context7 directement dans Claude Code.

Context7 permet d’injecter dans le contexte du modèle la documentation officielle d’une librairie, dans notre cas Vite, sans dépendre des données d’entraînement du modèle, potentiellement obsolètes pour une version aussi récente. Le résultat est un plan de migration précis, ancré sur la doc réelle de Vite 8, que nous avons pu valider et ajuster avant toute exécution.


3. Mise en place de la configuration Vite

La première étape concrète consiste à remplacer vue.config.js par vite.config.js et à mettre à jour package.json.

Dépendances à retirer

@vue/cli-service, @vue/cli-plugin-babel, vue-loader, babel-loader,
css-loader, sass-loader, style-loader, svg-inline-loader, @babel/core

Dépendances à ajouter

vite ^8.0.0
@vitejs/plugin-vue ^6.0.0
sass-embedded ^1.83.0

Pensez aussi à migrer vos librairies tieres qui dépende de webpack comme sentry par exemple : @sentry/webpack-plugin -> @sentry/vite-plugin

Structure de base du vite.config.js

import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'node:path'
import { fileURLToPath } from 'node:url'

const __dirname = fileURLToPath(new URL('.', import.meta.url))

export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd(), 'VITE_APP_')

  return {
    resolve: {
      alias: { '@': resolve(__dirname, 'src') },
      extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
    },
    css: {
      postcss: { plugins: [] },
    },
    build: {
      sourcemap: true,
      rollupOptions: {
        output: {
          entryFileNames: '[name].js',
          chunkFileNames: '[name].js'
        }
      }
    },
    server: { port: 8080, host: true }
  }
})

Point d’attention : l’extension .vue dans resolve.extensions

Webpack résolvait automatiquement les imports sans extension pour les fichiers .vue. Vite non. Il faut explicitement déclarer .vue dans resolve.extensions, sans quoi tous les imports de composants sans extension échouent avec une erreur Failed to resolve import.

Point d’attention : le css.postcss

@vue/cli-service dépose en dépendances transitives un fichier postcss.config.js qui tente de charger un plugin PostCSS incompatible. En définissant css.postcss: { plugins: [] } dans la config Vite, on neutralise ce chargement automatique.


4. Migration des variables d’environnement

Webpack (via vue-cli) exposait les variables préfixées VUE_APP_ via process.env. Vite expose les variables préfixées VITE_APP_ via import.meta.env.

Renommage dans les fichiers .env.*

sed -i 's/VUE_APP_/VITE_APP_/g' .env .env.integration .env.recette .env.production

Remplacement dans le code source

find src -type f \( -name "*.vue" -o -name "*.js" \) \
  -exec sed -i 's/process\.env\.VUE_APP_/import.meta.env.VITE_APP_/g' {} +

Ne pas oublier process.env.BASE_URL qui devient import.meta.env.BASE_URL (sans le préfixe VITE_APP_).

Éviter le conflit de nom de mode

Vite réserve le mot local comme suffixe pour les fichiers .env.local. Utiliser --mode local en argument de build provoque un comportement inattendu. Nous avons renommé notre mode local en local-dev pour contourner cette collision.


5. Remplacement des imports dynamiques Webpack

Webpack permettait d’utiliser require() avec des expressions dynamiques pour charger des fichiers à la volée. Ce pattern n’existe pas en ESM natif. Vite propose import.meta.glob() comme équivalent.

ESM (ECMAScript Modules) est le système de modules natif des navigateurs modernes. Contrairement à CommonJS (le système de Node.js historique), ESM permet au navigateur de charger les modules JavaScript directement via des imports/exports standardisés (import/export), sans nécessiter de bundler côté serveur.

Vite exploite cette capacité en développement pour servir les fichiers sources tels quels, ce qui élimine l’étape de compilation et offre un démarrage quasi instantané.

Avant (Webpack)

const image = require(`../assets/landings/${name}.jpg`)
const datas = require(`../landings/${landing}/datas.js`).default

Après (Vite)

const landingImages = import.meta.glob('../assets/landings/*.jpg', {
  eager: true, query: '?url', import: 'default'
})
const landingDatasMap = import.meta.glob('../landings/*/datas.js', {
  eager: true, import: 'default'
})

// Utilisation
const image = landingImages[`../assets/landings/${name}.jpg`]
const datas = landingDatasMap[`../landings/${landing}/datas.js`]

Pour les imports non-eager (chargement paresseux), import.meta.glob retourne un objet de fonctions d’import dynamique :

const formDatasModules = import.meta.glob('./forms/*/datas.js')

const path = `./forms/${formName}/datas.js`
const module = await formDatasModules[path]()

6. Les erreurs que nous avons rencontrées et leurs solutions

Voici une liste non exhaustive de types d’erreurs concrètes auxquelles nous avons été confrontés, et le moyen que nous avons mis en place pour les corriger.

PostCSS plugin vue-sfc-vars requires PostCSS 8

Cette erreur venait d’un conflit de version dans @vue/compiler-sfc. @vitejs/plugin-vue version 6.x requiert Vue 3.5+. Notre projet était encore sur Vue 3.4, qui embarquait une version de @vue/compiler-sfc utilisant PostCSS 7. La solution : monter Vue à ^3.5.0 et ajouter une résolution de dépendance dans package.json :

"resolutions": {
  "@vue/compiler-sfc": "^3.5.0"
}

Les imports SCSS avec ~

Webpack permettait de préfixer les chemins d’import SCSS par ~ pour indiquer un module node. Vite ne reconnaît pas ce préfixe. Tous les @import '~bootstrap/scss/...' doivent devenir @import 'bootstrap/scss/...'.

Les exports nommés ESM vs interop CJS de Webpack

C’est l’erreur la plus insidieuse. Webpack, via Babel, appliquait un interop CommonJS qui permettait d’importer en ESM des identifiants non exportés depuis un module CJS, retournant silencieusement undefined. En ESM natif, Vite lève une SyntaxError explicite.

Dans notre cas, une centaine de fichiers importaient des fonctions de validation (inputValidation, radioValidation…) depuis common.js, alors que ces fonctions n’y étaient pas définies mais dans validators.js. Webpack ne signalait rien, Vite plante au build. La solution : ajouter les re-exports manquants dans common.js :

export { radioValidation, inputValidation, /* ... */ } from './validators'

Chargement du web component sans type="module"

Notre application charge dynamiquement taro-funnel.js (le web component du projet dont nous avons fait la migration) via un élément <script> créé en JavaScript. Le build Vite produit des bundles ESM. Sans type="module" sur le tag script, le navigateur tente d’exécuter de l’ESM comme du script classique et lève :

Uncaught SyntaxError: Cannot use import statement outside a module

La correction est triviale mais non évidente :

const script = document.createElement('script')
script.type = 'module'  // indispensable pour un bundle ESM
script.src = src
document.head.appendChild(script)

7. Résultats et bilan

Ce que nous avons gagné

  • Build de production : de ~60s à ~15s (×4)
  • Nombre de ligne du yarn.lock diminué de ~1000 lignes en moins
  • Démarrage du serveur de dev : quasi instantané
  • Configuration : un seul fichier vite.config.js clair, sans accumulation de loaders
  • Des erreurs d’import qui étaient silencieuses sous Webpack sont maintenant détectées au build, ce qui améliore la qualité du code

Ce que la migration a révélé

La transition vers l’ESM strict est un révélateur de dette technique. Les imports invalides ou les exports manquants qui passaient inaperçus pendant des années sous Webpack remontent en surface. C’est un travail supplémentaire à court terme, mais un gain de fiabilité à long terme.

Durée de la migration

Sur un projet de cette complexité (multi-entrées, web component, ~110 specs de test, SCSS global), la migration (Webpack → Vite) a nécessité une journée de travail, fortement aidée par une analyse préalable de la codebase par Claude Code et la documentation live de Vite via Context7.


Conclusion

Migrer de Webpack vers Vite est aujourd’hui un investissement rentable sur pratiquement tous les projets Vue.

Les gains en temps de build sont immédiats et mesurables, la configuration résultante est plus simple à maintenir, et l’alignement avec l’écosystème Vue est un atout concret pour stabiliser et faire évoluer vos projets.


Liens utiles

Mathieu Ducrot
Mathieu Ducrot CTO
Mots clés :
#Qualité #Productivité

Articles similaires

Vous avez un projet ?

Contactez-nous pour savoir comment nous pouvons vous aider.