Trasformazione del codice senza configurazione con babel-plugin-macros
Questa pagina è stata tradotta da PageTurner AI (beta). Non ufficialmente approvata dal progetto. Hai trovato un errore? Segnala problema →
Babel è nato come transpiler per scrivere l'ultima versione della specifica ECMAScript e distribuire il codice in ambienti che non supportano ancora quelle funzionalità. Ma è diventato molto di più. "I compilatori sono i nuovi framework" afferma Tom Dale e non potrei essere più d'accordo. Vediamo sempre più ottimizzazioni a tempo di compilazione per librerie e framework. Non parlo di estensioni sintattiche del linguaggio, ma di semplici trasformazioni di codice che abilitano pattern altrimenti difficili da realizzare.
Uno degli aspetti che preferisco dei plugin per compilatori è che permettono di ottimizzare contemporaneamente l'esperienza utente e l'esperienza sviluppatore. (Leggi di più su "Come scrivere plugin personalizzati per Babel & ESLint può aumentare la produttività e migliorare l'esperienza utente").
Tuttavia, ho alcuni problemi con i plugin Babel:
-
Possono creare confusione perché esaminando il codice in un progetto, potresti non renderti conto che c'è un plugin che lo sta trasformando.
-
Devono essere configurati globalmente o esternamente (in un file
.babelrco nella configurazione webpack). -
Possono entrare in conflitto in modi molto confusi poiché tutti i plugin Babel vengono eseguiti simultaneamente (con un singolo attraversamento dell'AST di Babel).
Questi problemi potrebbero essere risolti se potessimo importare i plugin Babel e applicarli direttamente al nostro codice. Ciò renderebbe la trasformazione più esplicita, non dovremmo aggiungerli alla configurazione e l'ordine potrebbe seguire l'importazione dei plugin. Non sarebbe fantastico?
Presentazione di babel-plugin-macros 🎣
Indovinate! Esiste già uno strumento del genere! babel-plugin-macros è un nuovo plugin Babel che permette esattamente ciò di cui stiamo parlando. È un approccio "nuovo" alla trasformazione del codice. Consente trasformazioni di codice importabili senza alcuna configurazione. L'idea è di Sunil Pai e ha attirato la mia attenzione in questo issue di create-react-app.
Com'è nella pratica? Ebbene! Ci sono già diversi pacchetti babel-plugin-macros che puoi provare oggi stesso!
Ecco un esempio reale di utilizzo di preval.macro per incorporare un SVG in un'applicazione universale costruita con 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
Cosa c'è di interessante? L'alternativa sarebbe esattamente come l'esempio sopra, tranne per:
-
È meno esplicita perché non ci sarebbe
import preval from 'preval.macro'nel codice sorgente. -
Devi aggiungere
babel-plugin-prevalalla tua configurazione Babel. -
Devi aggiornare la configurazione ESLint per consentire la variabile
prevalcome globale. -
Se configuri male
babel-plugin-preval, otterrai un oscuro errore a runtime tipo:Uncaught ReferenceError: preval is not defined.
Utilizzando preval.macro con babel-plugin-macros, non abbiamo nessuno di questi problemi perché:
-
L'import è esplicitamente presente e utilizzato.
-
babel-plugin-macrosva aggiunto alla tua configurazione una sola volta, dopodiché puoi usare tutte le macro che vuoi (anche locali!). -
Non serve modificare la configurazione ESLint perché è tutto esplicito.
-
Se configuri male
babel-plugin-macros, otterrai un messaggio d'errore molto più chiaro in fase di compilazione che indica il problema specifico indirizzandoti alla documentazione.
Quindi cos'è realmente? In breve: babel-plugin-macros è un modo più semplice per scrivere e utilizzare trasformazioni Babel.
Esistono già diverse macro babel-plugin-macros pubblicate che puoi usare, tra cui preval.macro, codegen.macro, idx.macro, emotion/macro, tagged-translations/macro, babel-plugin-console/scope.macro e glamor 🔜.
Un altro esempio
babel-plugin-macros è un modo per avere zero configurazione per plugin Babel non sintattici. Molti plugin Babel esistenti potrebbero essere implementati come macro. Ecco un altro esempio di babel-plugin-console che espone una versione macro di se stesso:
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;
}
Ora, quando quel codice viene eseguito, la funzione scope fa cose piuttosto interessanti:
Browser:

Node:
Interessante vero? E usarlo è semplice come usare qualsiasi altra dipendenza, con tutti i vantaggi menzionati sopra.
Conclusione
Penso che abbiamo solo scalfito la superficie di ciò che babel-plugin-macros può fare. Spero di integrarlo in create-react-app così gli utenti di create-react-app potranno avere ancora più potenza senza configurazione. Sono entusiasta di vedere più plugin Babel esporre una macro oltre alla funzionalità plugin esistente. Non vedo l'ora che gli sviluppatori creino macro specifiche per le esigenze dei loro progetti.
Creare una macro è ancora più semplice di un normale plugin Babel, ma richiede comunque un po' di conoscenza sulle AST e Babel. Se questo concetto è nuovo per te, ci sono alcune risorse disponibili per te 😀
Buona fortuna a tutti! 👋
P.S. Vorrei sottolineare che le macro linguistiche non sono affatto un concetto nuovo. La capacità di insegnare nuovi trucchi a un linguaggio esiste da moltissimo tempo. Esiste già uno strumento simile per JavaScript e persino un'implementazione come plugin Babel. Tuttavia, babel-plugin-macros adotta un approccio leggermente diverso. Mentre le macro sono state tradizionalmente associate alla definizione di nuova sintassi per un linguaggio, non è affatto questo l'obiettivo di babel-plugin-macros. Nel caso di babel-plugin-macros, si tratta principalmente di trasformazioni del codice.