Articles

Configuration d’un projet ES6 à l’aide de Babel et de webpack

Dans cet article, nous allons examiner la création d’une configuration de construction pour gérer le JavaScript moderne (exécuté dans les navigateurs web) à l’aide de Babel et de webpack.

Ceci est nécessaire pour s’assurer que notre code JavaScript moderne en particulier est rendu compatible avec un plus grand nombre de navigateurs qu’il pourrait l’être autrement.

JavaScript, comme la plupart des technologies liées au web, évolue tout le temps. Au bon vieux temps, nous pouvions déposer quelques balises <script> dans une page, peut-être inclure jQuery et quelques plugins, puis être prêts à partir.

Cependant, depuis l’introduction de l’ES6, les choses se sont progressivement compliquées. La prise en charge par les navigateurs des nouvelles fonctionnalités du langage est souvent inégale, et comme les applications JavaScript deviennent plus ambitieuses, les développeurs commencent à utiliser des modules pour organiser leur code. À son tour, cela signifie que si vous écrivez du JavaScript moderne aujourd’hui, vous devrez introduire une étape de construction dans votre processus.

Comme vous pouvez le voir dans les liens ci-dessous, la conversion vers le bas de ES6 à ES5 augmente considérablement le nombre de navigateurs que nous pouvons prendre en charge.

  • Compatibilité ES6
  • Compatibilité ES5

Le but d’un système de build est d’automatiser le workflow nécessaire pour que notre code soit prêt pour les navigateurs et la production. Cela peut inclure des étapes telles que la transpilation du code vers une norme différente, la compilation de Sass en CSS, le regroupement de fichiers, la réduction et la compression du code, et bien d’autres. Pour s’assurer que ceux-ci sont répétables de manière cohérente, un système de construction est nécessaire pour lancer les étapes dans une séquence connue à partir d’une seule commande.

Prérequis

Pour suivre, vous devrez avoir à la fois Node.js et npm installés (ils sont livrés emballés ensemble). Je recommanderais d’utiliser un gestionnaire de version tel que nvm pour gérer votre installation de Node (voici comment), et si vous souhaitez un peu d’aide pour vous familiariser avec npm, alors consultez le tutoriel npm pour débutants de SitePoint.

Set Up

Créez un dossier racine quelque part sur votre ordinateur et naviguez dedans depuis votre terminal/ligne de commande. Ce sera votre dossier <ROOT>.

Créer un fichier package.json avec ceci :

npm init -y

Note : Le drapeau -y crée le fichier avec des paramètres par défaut, et signifie que vous n’avez pas besoin de compléter les détails habituels depuis la ligne de commande. Ils peuvent être modifiés dans votre éditeur de code plus tard si vous le souhaitez.

A l’intérieur de votre dossier <ROOT>, faites les répertoires src, src/js, et public. Le dossier src/js sera l’endroit où nous mettrons notre code source non traité, et le dossier public sera l’endroit où le code transpilé finira.

Transpiler avec Babel

Pour nous mettre en route, nous allons installer babel-cli, qui offre la possibilité de transpiler ES6 en ES5, et babel-preset-env, qui nous permet de cibler des versions de navigateurs spécifiques avec le code transpilé.

npm install babel-cli babel-preset-env --save-dev

Vous devriez maintenant voir ce qui suit dans votre package.json:

"devDependencies": { "babel-cli": "^6.26.0", "babel-preset-env": "^1.6.1"}

Pendant que nous sommes dans le fichier package.json, changeons la section scripts pour qu’elle se lise comme ceci:

"scripts": { "build": "babel src -d public"},

Cela nous donne la possibilité d’appeler Babel via un script, plutôt que directement depuis le terminal à chaque fois. Si vous souhaitez en savoir plus sur les scripts npm et ce qu’ils peuvent faire, consultez ce tutoriel SitePoint.

Enfin, avant de pouvoir tester si Babel fait son truc, nous devons créer un fichier de configuration .babelrc. C’est à ce fichier que notre paquet babel-preset-env se référera pour ses paramètres de transpilation.

Créer un nouveau fichier dans votre répertoire <ROOT> appelé .babelrc et y coller ce qui suit :

{ "presets": } } ] ]}

Cela configurera Babel pour transpiler pour les deux dernières versions de chaque navigateur, plus Safari à la v7 ou plus. D’autres options sont disponibles en fonction des navigateurs que vous devez prendre en charge.

Avec cette sauvegarde, nous pouvons maintenant tester les choses avec un exemple de fichier JavaScript qui utilise ES6. Pour les besoins de cet article, j’ai modifié une copie de leftpad pour utiliser la syntaxe ES6 à un certain nombre d’endroits : les littéraux de template, les fonctions flèches, const et let.

Save this as src/js/leftpad.js and from your terminal run the following:

npm run build

Si tout se passe comme prévu, dans votre dossier public vous devriez maintenant trouver un nouveau fichier appelé js/leftpad.js. Si vous l’ouvrez, vous constaterez qu’il ne contient plus aucune syntaxe ES6 et qu’il ressemble à ceci:

Organiser votre code avec les modules ES6

Un module ES6 est un fichier JavaScript contenant des fonctions, des objets ou des valeurs primitives que vous souhaitez mettre à la disposition d’un autre fichier JavaScript. Vous export de l’un, et import dans l’autre. Tout projet JavaScript moderne sérieux devrait envisager l’utilisation de modules. Ils vous permettent de décomposer votre code en unités autonomes et donc de rendre les choses plus faciles à maintenir ; ils vous aident à éviter la pollution des espaces de noms ; et ils contribuent à rendre votre code plus portable et réutilisable.

Alors que la majorité de la syntaxe ES6 est largement disponible dans les navigateurs modernes, ce n’est pas encore le cas des modules. Au moment de la rédaction de cet article, ils sont disponibles dans Chrome, Safari (y compris la dernière version iOS) et Edge ; ils sont cachés derrière un drapeau dans Firefox et Opera ; et ils ne sont pas disponibles (et ne le seront probablement jamais) dans IE11, ni dans la plupart des appareils mobiles.

Dans la prochaine section, nous examinerons comment nous pouvons intégrer des modules dans notre configuration de construction.

Export

Le mot-clé export est ce qui nous permet de rendre nos modules ES6 disponibles à d’autres fichiers, et il nous donne deux options pour le faire – nommé et par défaut. Avec l’exportation nommée, vous pouvez avoir plusieurs exportations par module, et avec une exportation par défaut, vous n’en avez qu’une par module. Les exportations nommées sont particulièrement utiles lorsque vous devez exporter plusieurs valeurs. Par exemple, vous pouvez avoir un module contenant un certain nombre de fonctions utilitaires qui doivent être rendues disponibles à divers endroits dans vos apps.

Donc, transformons notre fichier leftPad en un module, que nous pouvons ensuite exiger dans un deuxième fichier.

Exportation nommée

Pour créer une exportation nommée, ajoutez ce qui suit au bas du fichier leftPad:

export { leftPad };

Nous pouvons également supprimer la déclaration "use strict"; du haut du fichier, car les modules fonctionnent en mode strict par défaut.

Défaut d’exportation

Comme il n’y a qu’une seule fonction à exporter dans le fichier leftPad, il pourrait en fait être un bon candidat pour utiliser export default à la place :

export default function leftPad(str, len, ch) { ...}

A nouveau, vous pouvez supprimer la déclaration "use strict"; du haut du fichier.

Import

Pour faire usage des modules exportés, nous devons maintenant les importer dans le fichier (module) dans lequel nous souhaitons les utiliser.

Pour l’option export default, le module exporté peut être importé sous le nom que vous souhaitez choisir. Par exemple, le module leftPad peut être importé comme suit :

import leftPad from './leftpad';

Ou il peut être importé sous un autre nom, comme suit :

import pineapple_fritter from './leftpad';

Fonctionnellement, les deux fonctionneront exactement de la même manière, mais il est évidemment logique d’utiliser soit le même nom que celui sous lequel il a été exporté, soit quelque chose qui rend l’importation compréhensible – peut-être lorsque le nom exporté entrerait en conflit avec un autre nom de variable qui existe déjà dans le module récepteur.

Pour l’option d’exportation nommée, nous devons importer le module en utilisant le même nom que celui sous lequel il a été exporté. Pour notre module d’exemple, nous l’importerions d’une manière similaire à celle que nous avons utilisée avec la syntaxe export default, mais dans ce cas, nous devons envelopper le nom importé avec des accolades :

import { leftPad } from './leftpad';

Les accolades sont obligatoires avec une exportation nommée, et elle échouera si elles ne sont pas utilisées.

Il est possible de changer le nom d’une exportation nommée à l’importation si nécessaire, et pour ce faire, nous devons modifier un peu notre syntaxe en utilisant une syntaxe import as . Comme avec export, il y a une variété de façons de le faire, qui sont toutes détaillées sur la page d’importation MDN.

import { leftPad as pineapple_fritter } from './leftpad_es6';

Encore, le changement de nom est un peu absurde, mais il illustre le fait qu’ils peuvent être changés en n’importe quoi. Vous devriez vous en tenir à de bonnes pratiques de dénomination à tout moment, sauf bien sûr si vous écrivez des routines pour préparer des recettes à base de fruits.

Consommation du module exporté

Pour faire usage du module leftPad exporté, j’ai créé le fichier index.js suivant dans le dossier src/js. Ici, je boucle à travers un tableau de numéros de série, et je les préfixe avec des zéros pour les transformer en une chaîne de huit caractères. Plus tard, nous en ferons usage et les afficherons dans un élément de liste ordonnée sur une page HTML. Notez que cet exemple utilise la syntaxe d’exportation par défaut:

Comme nous l’avons fait précédemment, exécutez le script de construction à partir du répertoire <ROOT>:

npm run build

Babel va maintenant créer un fichier index.js dans le répertoire public/js. Comme pour notre fichier leftPad.js, vous devriez constater que Babel a remplacé toute la syntaxe ES6 et n’a laissé derrière lui que la syntaxe ES5. Vous pouvez également remarquer qu’il a converti la syntaxe du module ES6 en module.exports basée sur Node, ce qui signifie que nous pouvons l’exécuter à partir de la ligne de commande :

node public/js/index.js// 

Votre terminal devrait maintenant enregistrer un tableau de chaînes de caractères préfixées par des zéros pour qu’elles aient toutes huit caractères. Ceci étant fait, il est temps de jeter un coup d’œil à webpack.

Introducing webpack and Integrating it with Babel

Comme mentionné, les modules ES6 permettent au développeur JavaScript de décomposer son code en morceaux gérables, mais la conséquence de ceci est que ces morceaux doivent être servis au navigateur demandeur, ajoutant potentiellement des dizaines de requêtes HTTP supplémentaires en retour au serveur – quelque chose que nous devrions vraiment chercher à éviter. C’est là que webpack entre en jeu.

webpack est un regroupeur de modules. Son but premier est de traiter votre application en traquant toutes ses dépendances, puis de les empaqueter dans un ou plusieurs bundles qui peuvent être exécutés dans le navigateur. Cependant, il peut être bien plus que cela, selon la façon dont il est configuré.

La configuration de webpack s’articule autour de quatre composants clés :

  • un point d’entrée
  • un emplacement de sortie
  • loaders
  • plugins

Entrée : Ceci détient le point de départ de votre application à partir duquel webpack peut identifier ses dépendances.

Sortie : Ceci spécifie l’endroit où vous souhaitez que le paquet traité soit enregistré.

Loaders : Ceux-ci sont un moyen de convertir une chose en entrée et de générer autre chose en sortie. Ils peuvent être utilisés pour étendre les capacités de webpack à gérer plus que des fichiers JavaScript, et donc convertir ceux-ci en modules valides également.

Plugins : Ils sont utilisés pour étendre les capacités de webpack à d’autres tâches au-delà du regroupement – comme la minification, le linting et l’optimisation.

Pour installer webpack, exécutez ce qui suit à partir de votre répertoire <ROOT>:

npm install webpack webpack-cli --save-dev

Ceci installe webpack localement au projet, et donne également la possibilité d’exécuter webpack à partir de la ligne de commande grâce à l’ajout de webpack-cli. Vous devriez maintenant voir webpack listé dans votre fichier package.json. Pendant que vous êtes dans ce fichier, modifiez la section des scripts comme suit, de sorte qu’il sache maintenant utiliser webpack au lieu de Babel directement:

"scripts": { "build": "webpack --config webpack.config.js"},

Comme vous pouvez le voir, ce script fait appel à un fichier webpack.config.js, alors créons-le dans notre répertoire <ROOT> avec le contenu suivant:

C’est plus ou moins le fichier de configuration le plus simple dont vous avez besoin avec webpack. Vous pouvez voir qu’il utilise les sections d’entrée et de sortie décrites précédemment (il pourrait fonctionner avec ces seules sections), mais il contient également un paramètre mode: 'development'.

webpack a la possibilité d’utiliser les modes « développement » ou « production ». Le réglage mode: 'development' optimise la vitesse de construction et le débogage, tandis que mode: 'production' optimise la vitesse d’exécution au moment de l’exécution et la taille du fichier de sortie. Il y a une bonne explication des modes dans l’article de Tobias Koppers « webpack 4 : mode and optimization » si vous souhaitez en savoir plus sur la façon dont ils peuvent être configurés au-delà des paramètres par défaut.

Puis, supprimez tous les fichiers du dossier public/js. Puis réexécutez ceci :

npm run build

Vous verrez qu’il contient maintenant un seul fichier ./public/bundle.js. Ouvrez le nouveau fichier, cependant, et les deux fichiers avec lesquels nous avons commencé semblent plutôt différents. Voici la section du fichier qui contient le code index.js. Même s’il est assez fortement modifié par rapport à notre original, vous pouvez toujours repérer ses noms de variables :

Si vous exécutez node public/js/bundle.js à partir du dossier <ROOT>, vous verrez que vous obtenez les mêmes résultats que précédemment.

Transpiling

Comme mentionné précédemment, les chargeurs nous permettent de convertir une chose en quelque chose d’autre. Dans ce cas, nous voulons que ES6 soit converti en ES5. Pour ce faire, nous aurons besoin de quelques paquets supplémentaires :

npm install babel-loader babel-core --save-dev

Pour les utiliser, le webpack.config.js a besoin qu’une section module lui soit ajoutée après la section de sortie, comme ceci :

Cela utilise une déclaration regex pour identifier les fichiers JavaScript à transposer avec le babel-loader, tout en excluant tout ce qui se trouve dans le dossier node_modules de cela. Enfin, on dit au babel-loader d’utiliser le paquet babel-preset-env installé plus tôt, pour établir les paramètres de transpilation définis dans le fichier .babelrc.

Avec cela fait, vous pouvez réexécuter ceci:

npm run build

Puis vérifiez le nouveau public/js/bundle.js et vous verrez que toutes les traces de syntaxe ES6 ont disparu, mais il produit toujours la même sortie que précédemment.

Apporter au navigateur

Ayant construit une configuration webpack et Babel fonctionnelle, il est temps d’apporter ce que nous avons fait au navigateur. Un petit fichier HTML est nécessaire, et il devrait être créé dans le dossier <ROOT> comme ci-dessous :

Un peu plus de JavaScript est nécessaire pour afficher la liste, alors modifions ./src/js/index.js pour que cela se produise :

Maintenant, si vous ouvrez index.html dans votre navigateur, vous devriez voir une liste ordonnée apparaître, comme ceci:

Pour aller plus loin

Comme configuré ci-dessus, notre système de construction est à peu près prêt à partir. Nous pouvons maintenant utiliser webpack pour regrouper nos modules et transpiler le code ES6 vers le bas en ES5 avec Babel.

Cependant, c’est un peu un tic que, pour transpiler notre code ES6, nous devons exécuter npm run build chaque fois que nous faisons un changement.

Ajout d’un ‘watch’

Pour surmonter le besoin d’exécuter de façon répétée npm run build, vous pouvez mettre en place un 'watch' sur vos fichiers et faire en sorte que webpack recompile automatiquement chaque fois qu’il voit un changement dans l’un des fichiers du dossier ./src. Pour mettre en œuvre cela, modifiez la section scripts du fichier package.json, comme ci-dessous :

"scripts": { "watch": "webpack --watch", "build": "webpack --config webpack.config.js"},

Pour vérifier que cela fonctionne, exécutez npm run watch depuis le terminal, et vous verrez qu’il ne retourne plus à l’invite de commande. Maintenant, retournez à src/js/index.js et ajoutez une valeur supplémentaire dans le tableau serNos et enregistrez-la. Le mien ressemble maintenant à ceci:

const serNos = ;

Si vous vérifiez maintenant le terminal, vous verrez qu’il s’est déconnecté, et qu’il a ré-exécuté la tâche webpack build. Et en retournant au navigateur et en rafraîchissant, vous verrez la nouvelle valeur ajoutée à la fin de la liste, ayant été traitée avec leftPad.

Rafraîchir le navigateur automatiquement

Ce serait vraiment bien maintenant si nous pouvions obtenir que webpack rafraîchisse le navigateur automatiquement à chaque fois que nous faisons un changement. Faisons cela en installant un paquet npm supplémentaire appelé webpack-dev-server. N’oubliez pas de Ctrl + c hors de la tâche watch d’abord, cependant!

npm install webpack-dev-server --save-dev

Avec cela fait, ajoutons un nouveau script au fichier package.json pour appeler le nouveau paquet. La section scripts devrait maintenant contenir ceci:

Notez le drapeau --open-page ajouté à la fin du script. Cela indique à webpack-dev-server d’ouvrir une page spécifique dans votre navigateur par défaut en utilisant son mode iframe.

Maintenant, exécutez npm start et vous devriez voir un nouvel onglet de navigateur ouvert à avec la liste des pièces affichée. Pour montrer que le 'watch' fonctionne, allez à src/js/index.js et ajoutez une autre nouvelle valeur à la fin du tableau serNos. Lorsque vous enregistrez vos modifications, vous devriez les remarquer reflétées presque immédiatement dans le navigateur.

Avec cela terminé, la seule chose qui reste est que le mode dans webpack.config.js doit être défini à production. Une fois que cela est défini, webpack va également minifier le code qu’il sort en ./public/js/bundle.js. Vous devez noter que si le mode n’est pas défini, webpack utilisera par défaut la configuration production.

Conclusion

Dans cet article, vous avez vu comment configurer un système de construction pour le JavaScript moderne. Initialement, cela utilisait Babel depuis la ligne de commande pour convertir la syntaxe ES6 vers le bas en ES5. Vous avez ensuite vu comment utiliser les modules ES6 avec les mots-clés export et import, comment intégrer webpack pour effectuer une tâche de regroupement, et comment ajouter une tâche de surveillance pour automatiser l’exécution de webpack chaque fois que des modifications sont détectées dans un fichier source. Enfin, vous avez vu comment installer webpack-dev-server pour rafraîchir la page automatiquement chaque fois qu’un changement est effectué.

Si vous souhaitez aller plus loin, je vous suggère de lire la plongée profonde de SitePoint dans webpack et le regroupement de modules, ainsi que la recherche de chargeurs et de plugins supplémentaires qui permettront à webpack de gérer Sass et les tâches de compression des actifs. Regardez également le eslint-loader et le plugin pour Prettier aussi.

Happy bundling …

.