Dans ce chapitre je vous propose de faire le point sur l'outillage lié au langage JavaScript, car cela peut être assez rapidement compliqué lorsque l'on se renseigne. On entend parler de "Bundler", de "Transpiler", de "Formatter", de "Linter", de "Package Manager", et plein d'autres termes techniques qui ne sont pas forcément très évidents. Aussi je vous propose de faire le point sur le rôle de chacun de ces outils et vous donner quelques exemples d'utilisation.
Bundler
L'objectif d'un bundler est de combiner plusieurs fichiers JavaScript en un seul. Même si son principe est simple on peut se demander quel est l'intérêt d'un tel outil.
Dans un projet complexe, on va avoir tendance à séparer notre code en plusieurs petits fichiers en utilisant le système de modules (ce qui est une bonne pratique). Le problème c'est que la résolution des modules demandera plus de travail côté navigateur. À titre d'exemple, imaginons que l'on charge fichier "main.js", et on précise à notre navigateur que c'est un type module.
<script src="main.js" type="module">
Dans ce main.js, on a un code qui ressemble à ça.
import { hello } from './module1.js'
import { capitalize } from './module2.js'
hello(capitalize("john"))
Le navigateur doit faire une première requête HTTP pour trouver le fichier main.js
, ensuite il va devoir parser ce fichier-là (c'est-à-dire comprendre le code qu'il y a à l'intérieur) pour trouver l'ensemble des modules requis. Il va devoir ensuite charger ces modules, les parser, et trouver s'ils ont eux-mêmes des sous-modules. Et continuer de cette manière-là jusqu'à résoudre l'ensemble des modules utilisés par l'application. Donc s'il y a beaucoup de niveaux de profondeur, ce chargement en cascade va représenter un travail important à faire côté navigateur.
Les bundler vont faire cette résolution en amont et générer un fichier unique qui contiendra l'ensemble du code de l'application. Pour l'exemple précédent le code en sortie du bundler ressemblera à ça.
function hello (name) {
console.log('Bonjour ' + name);
}
function capitalize(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
hello(capitalize("john"))
Les fonctions des modules hello
et capitalize
ont été directement importées, et on se retrouve avec un seul fichier qui est plus facile à charger et à exécuter pour le navigateur. On a pris ici un cas simple mais les bundler sont capable de gérer des cas complexes en évitant les conflits dans les noms des variables par exemple.
Il existe pas mal de bundler dans l'écosystème actuel mais les plus connus sont :
- ESBuild, écrit en go, il est rapide et simple d'utilisation.
- SWC, écrit en rust, il a le même objectif qu'esbuild .
- Rollup, écrit en JavaScript. Il est plus lent mais aussi plus facilement extensible.
- Webpack, en perte de vitesse aujourd'hui car lent et complexe à configurer comparé aux autres outils.
- RSPack, écrit en rust, l'objectif est de proposer un outil compatible avec l'écosystème de webpack.
Pour une utilisation classique n'importe quel bundler peut convenir mais ils vont se comporter différemment lorsque vous allez chercher des fonctionnalités spécifiques (serveur de développement, watch mode, support de certains langages...).
Transpiler
Les transpiller permettent de convertir du code dans un langage particulier vers du JavaScript. Il y a plusieurs cas d'utilisation qui peuvent justifier l'utilisation d'un tel outil.
Le premier cas, c'est lorsque l'on souhaite écrire du code avec des fonctionnalités modernes qui ne sont pas encore supportées par l'environnement que l'on cible (l'exemple le plus récent est l'utilisation des décorateurs par exemple).
L'autre cas d'utilisation, un peu plus avancé, est l'utilisation de langages alternatifs au JavaScript. Par exemple, TypeScript qui permet d'ajouter la notion de Typage au code que l'on va écrire ou le JSX qui permet offre une syntaxe supplémentaire pour définir des éléments d'interface (utilisé par React notamment). Vu que les navigateurs ne supportent que le langage JavaScript il est nécessaire d'utiliser un transpiler pour convertir le code écrit dans ces langages alternatifs en JavaScript fonctionnel.
Le transpiler le plus connu est babel, qui permet principalement de rendre le code compatible sur un navigateur spécifique mais qui peut être étendu avec des extensions pour supporter plus de fonctionnalités. Il y a aussi tsc qui est le transpiler de TypeScript.
Enfin, certains bundler comme ESBuild sont aussi capables de gérer une étape de transpilation en plus de la création de bundle.
Linter
Les linters permettent une analyse statique du code et qui vont être capables de détecter les problèmes sans avoir à éxécuter le code.
- Il vérifie la syntaxe pour signaler les erreurs de syntaxe dans le code (variables mal orthographiées, parenthèses manquantes, guillemets mal placés...).
- Il veille à ce que le code respecte les bonnes pratiques en signalant du code potentiellement dangereux ou peu efficace (boucle infinie, mauvaise utilisation de certaines fonction...)
- Il assure un bon formatage du code (ligne pas trop longue, respect du nombre d'espace pour indenter...)
Plusieurs outils sont capables de lint mais le plus connu est eslint. Vous pouvez d'ailleurs le tester gràce à la page de démonstration qui vous permettra de tester son fonctionnement sur votre code mais aussi de générer un fichier de configuration que vous pourrez utiliser dans votre projet.
Aussi, cet outil peut être utilisé directement dans votre éditeur afin de détecter les erreurs le plus rapidement possible (via une extension pour VSCode, il est préintégré dans les éditeurs JetBrains).
Formatter
Les formatter sont des outils plus spécifiques qui se focalisent sur le formattage du code pour résoudre les différences de style de codage entre les différents membres d'une équipe. Ils facilitent la lisibilité et la compréhension du code et simplifie ainsi la collaboration.
L'outil le plus connu pour formater le code est prettier qui a l'avantage d'être préconfiguré avec un certains nombre de règles et il dispose d'une bonne intégration dans les éditeurs (comme pour ESLint il est supporté de base dans les éditeurs JetBrains et il existe une extension pour VSCode). Il est aussi possible de l'utiliser pour de l'HTML et du CSS.
Package manager
Les package manager vont nous permettre d'intégrer des librairies tierces dans notre application afin de ne pas avoir à réinventer la roue. Ils vont permettre de télécharger les librairies et si nécessaire les dépendances associées. Pour la gestion de ces librairies on va se baser sur l'environnement de NodeJS (qui permet de créer du JavaScript côté serveur) et son registre npmjs.
Il existe plusieurs outils qui peuvent être utilisé de manière interchangeable :
- npm, le gestionnaire classique de NodeJS
- yarn
- pnpm, optimise l'utilisation du disque et la rapidité d'installation
Ensuite, pour pouvoir utiliser les librairies tierces, vous pouvez utiliser le bundler qui permettra de résoudre le chemin de ces dépendances.
import prettyBytes from 'pretty-bytes';
prettyBytes(1337);
//=> '1.34 kB'
Dans ce cas là, le bundler sera capable de trouver quel fichier importer lorsqu'on importe un module provenant de npmjs (cf cette vidéo sur la résolution dans le dossier node_modules).
Starter kit
Cette multiplication d'outils a un effet néfaste : commencer un nouveau projet devient complexe avec une multitude d'outils à installer et à configurer. Heureusement pour nous, des développeurs se sont penchés sur ce problème et ont créé des outils pour simplifier le démarrage.
En ce moment, si on veut travailler sur du front-end, l'outil qui fait l'unanimité est vitejs qui intègre un bundler pour la phase de développement et de production. La création de projet se fait gràce à l'utilisation d'un package manager.
npm create vite@latest
Il vous posera quelques question sur la configuration que vous souhaitez et une fois ces questions répondues, il créera les fichiers qui vous permettront de commencer votre projet.
Si vous travailler avec un frameworks backend (Symfony, Laravel, Rails et Django), ils intègrent souvent une configuration pré-établie pour la gestion des assets qui vous évitera le travail de configuration.
- Symfony dispose de Encore qui offre une configuration webpack fonctionnant avec le framework.
- Laravel intègre une configuration vite de base.
- Ruby on Rails intègre une configuration pour webpack via l'outil webpacker.
- Des librairies existe pour intégrer vite ou webpack à Django.