Introduction

Incontournable de l’écosystème JavaScript, Create React App (ou CRA pour les intimes) est utilisé pour « scaffolder » / initialiser un nouveau projet React. La majorité des frameworks orientés composants disposent de leur outil CLI (« officiel« ) pour ce type de tâche : @angular/cli a.k.a ng, @vue/cli a.k.a vue, etc…

Pourtant, depuis quelques années (2020), un nouvel outil émerge, popularisé par la communauté open-source (et Evan You, son créateur) : Vite !

À l’instar de CRA qui se repose majoritairement sur Webpack pour fournir un projet JS/TS prêt à l’emploi ; Vite s’appuie sur ESBuild (et l’interface intuitive de Rollup) pour créer un nouveau projet Web. En 2023, Vite s’impose comme un acteur majeur du Web actuel et à venir, en apportant les fonctionnalités suivantes :

La puissance d'ESM (ECMA Script Module) lors du développement

Là où CRA s’appuie sur la syntaxe CommonJS, tout en ajoutant des plugins Babel pour le support de fonctionnalités modernes, telles que import / export, etc… Vite supporte nativement (et implicitement) la syntaxe .esm.

En d’autres termes, vous pouvez développer directement avec async / await (au plus haut niveau), ou encore importer directement vos fichiers .tsx / .jsx dans le point d’entrée de l’application (index.html) sans vous soucier de la phase de compilation.

Les ESM (ou explicitement les fichiers .mjs) disposent de leur propre contexte qui leur permet d’interpréter la dernière syntaxe supportée par l’environnement JS (les navigateurs / NodeJS). * Ensuite, Vite s’occupera de compiler tout cela pour vous !

*NB : Le passage de votre projet au format ESM, résulte de la valorisation de la clé type à module dans le package.json. L’impact de cela concerne vos fichiers .js « classique« , c’est-à-dire au format CommonJS. Typiquement les fichiers de configuration, tels que .eslintrc.js ou prettier.config.js (dans lesquels se trouve cette instruction : module.exports = {}), auront besoin d’être suffixé .cjs pour fonctionner dans un environnement ESM. En effet, un projet « module » ne supporte implicitement pas la syntaxe CommonJS, de même que pour les projets par défaut (non-ESM), qui devront utiliser la mention .esm pour supporter nativement certaines fonctionnalités avancées.

Rapide par défaut

1. La rapidité au développement 🚀

Le passage de Webpack à Vite s’accompagne d’un fonctionnement différent au niveau du serveur de développement.

Avec Webpack, la mise à disposition d’un environnement de développement, nécessite de parcourir toutes les ressources (fichiers JS, composants JSX, et autres modules…) pour ensuite lancer le serveur de développement.

Avec le support natif des modules ECMAScript (rendu possible par ESBuild), Vite exécute d’abord le serveur de développement, puis charge chaque ressource au besoin (à la manière du « code-splitting« ).

Fonctionnement du serveur de développement Webpack
Fonctionnement du serveur de développement Vite

2. La rapidité à la compilation 🚀 

L’autre changement notable avec Vite (et React) est le support de Speedy Web Compiler (SWC pour les intimes).

Lors du passage de Webpack à ESBuild, vous aurez la possibilité de conserver votre « bon vieux » compilateur Babel pour empaqueter (packager / builder) votre application, ou bien passer à son équivalent Rust (théoriquement 20x plus rapide).

Actuellement, toutes les librairies s’appuyant sur Vite ne bénéficie pas cette fonctionnalité… Mais pour ce qui est de React, il existe un plugin stable, donc autant profiter de cet avantage ! 😉

Maintenabilité

En 2023, Vite est plus que mature avec ces 4 versions majeures ! Contrairement à Create React App dont les mises à jour sont de plus en plus lentes, la communauté open-source à cœur de mettre à niveau son nouvel outil de développement Frontend ! Aussi, Vite propose actuellement 7 frameworks orientées composants au choix (avec un environnement TypeScript prêt à l’emploi), en plus de VanillaJS :

npm create vite@latest
✔ Project name: … hello-world
? Select a framework: › - Use arrow-keys. Return to submit.
    Vanilla
    Vue
❯   React
    Preact
    Lit
    Svelte
    Solid
    Qwik
    Others

Certains d’entre ces grands frameworks * ont déjà fait le choix de migrer leur outil CLI vers Vite (notamment vue, mais aussi svelte qui a « abandonné » degit au profit de ce dernier). Il est peut-être temps de s’y mettre !

*NB : Depuis la version 16 d’Angular (Mai 2023), le framework développé par Google propose un « preset » ESBuild, afin d’optimiser les performances de développement.

Migration (étape-par-étape)

Initialisation

La 1ère étape de ce travail de migration consiste à initialiser un nouvel environnement React basé sur Vite (plutôt que d’installer une à une les dépendances nécessaires au projet…). Pour ce faire, je vous recommande de suivre les différentes instructions suite à l’usage de la commande suivante : npm create vite@latest

Vous devriez vous retrouver avec une structure similaire, relativement proche de Create React App :

/
├── public/
├── src/
│   ├── assets/
│   ├── App.css
│   ├── App.tsx
│   ├── index.css
│   ├── main.tsx
│   └── vite-env.d.ts
├── .eslintrc.cjs # Oh ! CommonJS Syntax :)
├── index.html
├── package.json
├── tsconfig.json
└── tsconfig.node.json
└── vite.config.ts

Si on regarde en détail, notamment dans le package.json il n’y a plus de référence à react-script (indispensables aux projets CRA), qui se chargeait d’exécuter les tâches propres à Webpack (start, build, test). Cette fois-ci, tout repose sur Vite. *

*NB : De même, le script npm run preview disponible avec Vite, est équivalent à npx serve -s build préconisé par Create React App (et Vercel) pour tester le livrable final de votre application Web.

Configuration

NB : À ce stade-là, je vous invite à mettre en place une stratégie de formatage de fichiers (via Prettier 😎👌) et de configurer ESLint en fonction de votre besoin.

Vous l’aurez compris, la 2ème étape consiste à configurer votre nouveau projet. Pour ce faire, la majeure partie du travail se déroule dans le fichier vite.config.js.

Si vous êtes passé par l’instruction CLI suivante : npm create vite@latest lors de l’initialisation, vous devriez déjà avoir une configuration à jour !

Pour autant, ajoutons-y le support des SVGs (depuis les import) ainsi que vos potentiels alias de référence de module : npm i -D vite-plugin-svgr

import path from 'path';
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react-swc';
import svgr from 'vite-plugin-svgr';

export default defineConfig({
  plugins: [react(), svgr()],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
      '~': path.resolve(__dirname, './src')
    }
  }
});

La propriété baseUrl associée aux paths est primordiale pour la compilation TypeScript, ainsi que l’usage de la fonctionnalité « hyperlink » depuis l’IDE. Vous pouvez également utiliser la configuration ci-dessous dans un fichier jsconfig.json pour les projets JavaScript (non-TS).

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"],
      "~/*": ["src/*"]
    }
  }
}

Autre fichier à modifier (surement le plus important !? 🤔), le point d’entrée de votre application : l’index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <!-- Before -->
    <!-- <link rel="icon" type="image/png" href="%PUBLIC_URL%/favicon.png" /> -->
    <!-- After -->
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + React + TS</title>
  </head>
  <body>
    <div id="root"></div>
    <!-- Oh ! ESM Syntax :D -->
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>

✂️ Copier / 📋 Coller

Ctrl +C / +V

L’étape qui suit consiste tout simplement à copier / coller les sources présentes dans votre projet précédent / vers votre nouvelle structure Vite. Si vous n’êtes pas sortie du cadre CRA, il suffit de déplacer le contenu du dossier src vers celui de Vite, tout en faisant attention aux références dans le point d’entrée JavaScript de votre projet : main.tsx

NB : Pensez aux alias ! Veillez à ce que l’ensemble de vos imports soit en adéquation avec votre configuration vite.config.js / tsconfig.json ou jsconfig.json.

Pensez également à modifier l’accès aux variables d’environnement depuis process.env vers import.meta.env (à la manière de la syntaxe ESM).

Tests !!! ⚙️

Vitest is the new Jest

N’oublions pas les tests durant ce travail de migration !

CRA préconise d’utiliser Jest pour les tests unitaires (ce qui est déjà un bon choix). Si vous avez un projet pré-configuré avec Jest, la migration devrait aller plutôt « vite » 🙃

Commençons par installer les nouvelles dépendances relatives à Vitest (remplaçant de Jest) : npm i -D vitest @vitest/coverage-v8 @testing-library/jest-dom @testing-library/react jsdom

Puis configurez votre projet pour supporter Vitest en tant que variable globale :

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react-swc';
import svgr from 'vite-plugin-svgr';

export default defineConfig({
  // ...
  test: {
    globals: true,
    environment: 'jsdom',
    setupFiles: ['src/setupTests.ts'],
    coverage: {
      provider: 'v8',
      include: ['src/**/*.{js,jsx,ts,tsx}']
    }
  }
});
{
  "compilerOptions": {
    "types": ["vitest/globals"]
  }
}

Enfin, remplacez toutes les références à Jest par Vitest, selon l’exemple suivant :

import { vi } from 'vitest';
import { fireEvent, render, screen } from '@testing-library/react';
import MyComponent from '../MyComponent';

test('should triggers click event', () => {
  const onClickMock = vi.fn(); // jest.fn();
  render(<MyComponent onClick={onClickMock} />);
  fireEvent.click(screen.getByText('Click Me'));
  expect(onClickMock).toHaveBeenCalled();
});

L’API de Vitest, est très proche de Jest, puisque entièrement inspiré par ce dernier. À quelques exceptions : importActual. Il ne tient qu’à vous d’exécuter quelques tests : npx vitest ; ou avec la couverture de code : npx vitest — run –coverage

NB : Il est possible d’emuler Vitest dans une interface plus fluide avec la dépendance @vitest/ui. Je vous invite à tester cela, en exécutant simplement l’instruction suivante : npx vitest — –ui

À l’issue de cette dernière étape, vous aurez entièrement migré votre application Web de CRA à Vite (ou en tout cas 99% de votre projet). Bravo ! 👏 Et… Bienvenue dans la modernité 🎉🎊

Conclusion

La migration de Create React App à Vite ne change pas le contenu de l’application… En revanche, il améliore considérablement l’eXpérience de Développement (DX), avec notamment la prise en charge du « Hot Module Replacement » (HMR), permettant de changer les ressources du projet, sans devoir redémarrer le serveur de développement.

D’autre part, la communauté React peut profiter de la puissance de Rust, grâce à un plugin prêt à l’emploi, pour gagner en performances lors de la compilation du projet. Je suppose que d’autres frameworks orientés composants suivront le mouvement…

Enfin, le changement de Test Runner (de Jest à Vitest) permet également de booster les performances lors de l’exécution des tests unitaires, du fait d’une librairie plus légère (et moderne).

Malgré son jeune âge (comparé aux autres), Vite est de plus en plus utilisé (de même que ESBuild) avec plus de 6 millions de téléchargements NPM en Août 2023 (cf. NPM Trends), contrairement à Webpack, qui voit son nombre d’utilisateurs décliner…

NB : À noter que, Vite bénéficie d’une multitude de plugins communautaires tels que la prise en charge d’Electron, le support de Storybook ou encore l’ajout du mode PWA.

Opter pour Vite, c’est avoir un coup d’avance dans le développement Web, du fait de sa simplicité, de sa compatibilité avec Rollup, mais aussi de par la possibilité de changer de frameworks (à tout moment) sans rupture majeure : « un bundler pour les gouverner tous !« 

This website stores cookies on your computer. Cookie Policy