Loupe

Les macros Babel - L’avenir

Hello !

Maintenant que nous avons découvert Babel et vu comment l'utiliser avec Typescript, il est temps de vous parler des macros Babel.

Dans l’article précèdent, nous avions vu comment les plugins Babel permettaient “d’étendre” les capacités de Babel et ainsi avoir plusieurs logiques de traitement sur notre code. Nous avions pris l’exemple du preset-typescript qui permettait d’avoir un traitement sur notre code en supprimant le code Typescript. Nous aurions pu également citer babel-plugin-transform-remove-console qui permet de supprimer les console.log() de notre code ou encore @babel/plugin-transform-regenerator qui permet l’utilisation de fonctions generators en javascript. Si ça vous intéresse, vous pouvez retrouver la liste des principaux plugins de Babel ici.

Ces plugins précédemment cités ont un impact sur la compilation du code (minifications, optimisations, cleaning de code), mais il existe également des plugins qui vont changer comment notre code va être exécuté au runtime. Ainsi, des plugins comme babel-plugin-console vont  remplacer durant la compilation nos console.log() par une version nettement améliorée qui va log à la place dans la console la call stack, les paramètres de la fonction courante et les variables du scope courant.

Ici, notre plugin Babel n’a plus seulement un traitement à la compilation, il a un impact sur notre runtime en remplaçant en amont du code. Sympa non ? Sympa oui mais il y a malgré tout quelques soucis à cela :

  • Si l’on reprend notre exemple du babel-plugin-console, tous nos console.log vont être remplacés, peu importe où ils sont.
  • Une personne ne connaissant pas le projet et qui lit le code ne saura pas que les console.log vont être remplacés ou supprimés.
  • Ces plugins doivent être enregistrés dans notre .babelrc et certains nécessitent de la configuration qui va encore une fois être globale à tous les traitements.
  • Ils peuvent entrer en conflit  avec d’autres plugins du même genre durant la compilation ; en effet, tous les plugins Babel sont run en même temps lors de la compilation.

Qu'est-ce qu'une macro Babel ?

Afin de régler l’ensemble de ces problèmes tout en profitant de ce que Babel a de meilleur à nous offrir, un paquet npm a vu le jour : babel-plugin-macro. Comme vous l’avez compris, ce plugin va nous permettre l’utilisation de macro, mais c’est quoi une macro ?

Une macro n’est pas quelque chose de nouveau dans le monde du développement. C'est tout simplement l’ajout d’une syntaxe custom dans le but d’améliorer un langage. En ce qui concerne Javascript, il existe des librairies comme Sweet.js qui permettent de faire cela.

Ici, nous parlons de macros Babel et même si le principe de babel-plugin-macros va également dans ce sens, on parle davantage de transformation de code plutôt que d’ajout de nouvelles syntaxes à Javascript. Les macros Babel vont donc nous permettre de transformer du code par autre chose lors de la compilation. Jusque là, si vous suivez bien, vous me direz que c’est sensiblement ce que propose un plugin classique de Babel et c’est exact, à quelques différences près qui en font quelque chose de bien à part :

  • Une macro Babel est une transformation scopée : on a donc le contrôle sur ce que l’on veut transformer ou pas.
  • Une macro se caractérisant par un appel explicite, c’est beaucoup plus visuel pour le développeur.
  • Une macro n’a pas besoin d’être enregistrée dans le .babelrc et ne nécessite donc pas de configuration de setup.
  • Une macro étant scopée, il n’y a plus de risque de conflits possible.

Afin que cela soit plus parlant, voyons un exemple avec une macro nommée paths.macro. Cette macro va nous permettre d’importer la localisation du fichier source de notre projet comme l’explique sa documentation.

Tout d’abord, faisons-en sorte que nos macros puissent être reconnues par Babel, pour ça il nous faut installer babel-plugin-macros.

> npm install --save-dev babel-plugin-macros

Puis ajoutons ce plugin dans notre .babelrc :

{
	"plugins":  ["macros"]
}

Une fois cela fait, toutes les macros que vous utiliserez seront disponibles et reconnues par babel-plugin-macros, c’est la seule configuration nécessaire ! :)

Maintenant, installons notre macro :

> npm install --save-dev paths.macro

Désormais il ne nous reste plus qu’à nous en servir !

Pour reprendre l’exemple de la documentation :

import  base,  {  filename  }  from  'babel-plugin-module-paths/paths.macro';

console.log(base, filename);

alert(filename, base);

function  usePathsForSomething()  {
	return  [filename, base];
};

Ici, nous avons importé nos différentes macros, à savoir base et filename. Puis nous les avons utilisées dans notre code comme de simples variables (certaines macros sont des fonctions).
Lors de la compilation par Babel, ces variables seront reconnues et seront transformées. Ainsi nous aurons en output :

console.log("/src/",  "input");

alert("input",  "/src/");

function  usePathsForSomething()  {
	return  ["input",  "/src/"];
};

Magique non ? J’aurais pu également vous parler d’une autre macro nommée files.macro. L’installation en est similaire (à l’exception de babel-plugin-macro qui est déjà installé et configuré) : vous installez le paquet via npm et vous pouvez directement vous en servir. Cette macro nous permet de définir un path et, lors de la compilation, de transformer notre path en un tableau de filename des fichiers qui sont présents dans ce path.

Ainsi, et toujours selon la documentation de la macro,

import  files  from  "files.macro";

const  allImages  =  files("./assets/images");

devient :

const  allImages  =  [  'avatar.png',  'catalog.png'  ]

Vous pouvez retrouver les macros les plus populaires actuellement ici.

Ajouter de la configuration à une macro

Même si la philosophie derrière les macros est de ne justement pas avoir besoin d’ajouter de la configuration. Il se peut que vous soyez contraint d’en ajouter afin de personnaliser le comportement d’une macro.

Pour configurer vos macros, il suffit d’ajouter un fichier à la racine de votre projet respectant la syntaxe de nommage de cosmiconfig puisque c’est ce qu’utilise babel-config-macros.

Ensuite, dans le fichier de configuration vous avez juste à ajouter votre configuration comme ceci :

// babel-plugin-macros.config.js
module.exports = {
  // ...
  macroNameInLowerCamelCase: {
    key: value,
  },
}

Babel, les macros et l'avenir

En prenant en compte ce que l’on vient de dire, ajouté à ce que l’on a pu voir dans le précèdent article parlant de Babel et Typescript, l’avenir pour Babel au sein de l’écosystème Javascript s’annonce encourageant.

En effet, la tendance actuelle dans le monde Javascript est d’écrire de moins en moins de Javascript vanilla directement compréhensible par le navigateur. Tout cela s’explique par la présence de plus en plus importante de code transpilé (frameworks, presets, plugin) qui rend notre code javascript toujours plus performant et toujours plus optimisé.

Et il se trouve que Babel, en tant que compilateur de référence pour la transpilation de code javascript, a tous les outils pour répondre à cette tendance. Grace à sa capacité à traiter un très grand nombre de formats dû à ses nombreux plugins et presets faciles à configurer, il a des chances de devenir à terme l’unique compilateur de référence lorsqu’il s’agit de faire du javascript.

Pour conclure, je vous conseille cet excellent article d’un influenceur JS qui explique très bien cette tendance à avoir du code javascript toujours moins vanilla mais beaucoup plus performant grâce à l’avènement notamment de transpileurs comme Babel.

Et voilà qui conclut cette petite série sur Babel ! On se retrouve prochainement dans une nouvelle série parlant de CSS-in-JS rendu notamment possible grâce à Babel et ses macros :P

Happy Coding !

Ces billets pourraient aussi vous intéresser

Vous nous direz ?!

Commentaires

comments powered by Disqus