Transformation de code sans configuration avec babel-plugin-macros
Cette page a été traduite par PageTurner AI (bêta). Non approuvée officiellement par le projet. Vous avez trouvé une erreur ? Signaler un problème →
Babel a commencé comme un transpileur permettant d'écrire la dernière version de la spécification ECMAScript tout en ciblant des environnements ne supportant pas encore ces fonctionnalités. Mais il est devenu bien plus que cela. "Les compilateurs sont les nouveaux frameworks" déclare Tom Dale et je ne pourrais être plus d'accord. Nous observons de plus en plus d'optimisations à la compilation pour les bibliothèques et frameworks. Je ne parle pas d'extensions de syntaxe du langage, mais de transformations de code simples permettant des patterns difficiles à réaliser autrement.
Ce que je préfère dans les plugins de compilation, c'est qu'ils permettent d'optimiser simultanément l'expérience utilisateur et l'expérience développeur. (Lisez-en plus sur "Comment l'écriture de plugins Babel & ESLint personnalisés peut augmenter la productivité et améliorer l'expérience utilisateur").
Cependant, j'ai quelques problèmes avec les plugins Babel :
-
Ils peuvent créer de la confusion car lorsqu'on examine du code dans un projet, on peut ignorer qu'un plugin transforme ce code.
-
Ils nécessitent une configuration globale ou hors-contexte (dans un
.babelrcou une config webpack). -
Ils peuvent entrer en conflit de manière très confuse car tous les plugins Babel s'exécutent simultanément (lors d'un seul parcours de l'AST de Babel).
Ces problèmes pourraient être résolus si nous pouvions importer des plugins Babel et les appliquer directement à notre code. Cela rendrait la transformation plus explicite, éliminerait le besoin de les ajouter à la configuration, et l'ordre pourrait suivre l'import des plugins. Ne serait-ce pas génial ?!
Présentation de babel-plugin-macros 🎣
Devinez quoi ! Un tel outil existe ! babel-plugin-macros est un nouveau plugin Babel permettant exactement ce dont nous parlons. C'est une approche "nouvelle" de la transformation de code. Il offre des transformations de code importables sans configuration. L'idée vient de Sunil Pai et a retenu mon attention dans cette issue create-react-app.
Alors à quoi cela ressemble-t-il ? Eh bien ! Il existe déjà plusieurs packages babel-plugin-macros que vous pouvez essayer dès aujourd'hui !
Voici un exemple réel d'utilisation de preval.macro pour intégrer un SVG dans une application universelle construite avec Next.js :
// search.js
// this file runs in the browser
import preval from 'preval.macro'
import glamorous from 'glamorous'
const base64SearchSVG = preval.require('./search-svg')
// this will be transpiled to something like:
// const base64SearchSVG = 'PD94bWwgdmVyc2lv...etc...')
const SearchBox = glamorous.input('algolia_searchbox', props => ({
backgroundImage: `url("data:image/svg+xml;base64,${base64SearchSVG}")`,
// ...
}))
// search-svg.js
// this file runs at build-time only
// because it's required using preval.require function, which is a macro!
const fs = require('fs')
const path = require('path')
const svgPath = path.join(__dirname, 'svgs/search.svg')
const svgString = fs.readFileSync(svgPath, 'utf8')
const base64String = new Buffer(svgString).toString('base64')
module.exports = base64String
Qu'est-ce qui est cool là-dedans ? Eh bien, l'alternative ressemblerait exactement à l'exemple ci-dessus sauf que :
-
C'est moins explicite car il n'y aurait pas d'
import preval from 'preval.macro'dans le code source. -
Vous devez ajouter
babel-plugin-prevalà votre configuration Babel. -
Vous devez mettre à jour votre configuration ESLint pour autoriser la variable
prevalcomme globale. -
Si vous configurez mal
babel-plugin-preval, vous obtiendrez une erreur d'exécution cryptique comme :Uncaught ReferenceError: preval is not defined.
En utilisant preval.macro avec babel-plugin-macros, nous n'avons aucun de ces problèmes car :
-
L'importation est présente et utilisée explicitement.
-
babel-plugin-macrosdoit être ajouté à votre configuration, mais une seule fois, puis vous pouvez utiliser toutes les macros souhaitées (même locales !) -
Aucune mise à jour de la configuration ESLint n'est nécessaire car tout est explicite.
-
Si vous configurez mal
babel-plugin-macros, vous obtiendrez un message d'erreur de compilation bien plus clair qui pointe le problème réel et vous oriente vers la documentation.
Alors de quoi s'agit-il vraiment ? En bref : babel-plugin-macros est un moyen plus simple d'écrire et d'utiliser des transformations Babel.
Plusieurs macros babel-plugin-macros sont déjà publiées, notamment preval.macro, codegen.macro, idx.macro, emotion/macro, tagged-translations/macro, babel-plugin-console/scope.macro, et glamor 🔜.
Autre exemple
babel-plugin-macros permet d'éviter toute configuration pour les plugins Babel non liés à la syntaxe. Ainsi, de nombreux plugins Babel existants pourraient être implémentés comme macros. Voici un autre exemple avec babel-plugin-console qui propose une version macro :
import scope from 'babel-plugin-console/scope.macro'
function add100(a) {
const oneHundred = 100
scope('Add 100 to another number')
return add(a, oneHundred)
}
function add(a, b) {
return a + b;
}
Lorsque ce code est exécuté, la fonction scope réalise des opérations plutôt astucieuses :
Navigateur :

Node :
Intéressant, non ? Son utilisation est identique à n'importe quelle dépendance, mais avec tous les avantages mentionnés précédemment.
Conclusion
Nous n'avons fait qu'effleurer le potentiel de babel-plugin-macros. J'espère son intégration dans create-react-app pour offrir plus de puissance sans configuration aux utilisateurs de create-react-app. J'attends avec impatience que plus de plugins Babel proposent une macro en complément de leurs fonctionnalités existantes. Et je suis impatient de voir émerger des macros spécifiques aux besoins de chaque projet.
Créer une macro est encore plus simple qu'un plugin Babel classique, mais cela nécessite quelques connaissances sur les AST et Babel. Si ce domaine vous est inconnu, voici quelques ressources pour vous 😀
Bonne chance à tous ! 👋
P.S. Je dois mentionner que les macros de langage ne sont pas du tout un concept nouveau. La capacité d'enseigner de nouvelles astuces à un langage existe depuis très longtemps. En fait, il existe déjà un tel outil pour JavaScript et même un autre implémenté en tant que plugin Babel. Cependant, babel-plugin-macros adopte une approche légèrement différente. Alors que les macros ont souvent été associées à la définition d'une nouvelle syntaxe pour un langage, ce n'est pas du tout l'objectif de babel-plugin-macros. Dans le cas de babel-plugin-macros, il s'agit davantage de transformations de code.