Vai al contenuto principale

Babili (babel-minify)

· Lettura di 9 min
Traduzione Beta Non Ufficiale

Questa pagina è stata tradotta da PageTurner AI (beta). Non ufficialmente approvata dal progetto. Hai trovato un errore? Segnala problema →

Abbiamo rilasciato Babili in versione beta (0.0.1) pochi giorni fa con licenza MIT!

Provalo nel REPL di Babel e segnala eventuali bug o ottimizzazioni possibili! C'è anche una room Slack dedicata #minify!

Sorgono molte domande (legittime) sul perché sia utile un nuovo minificatore, e questo post vuole rispondere proprio a quelle.

TL;DR: Babili accetta input ES2015+, mentre gli attuali minificatori sono limitati principalmente a ES5, richiedendo transpilazione prima della minificazione. Ciò diventa superfluo man mano che si inizia a distribuire ES2015 ai client. Babili è inoltre modulare/flessibile (essendo un preset Babel supporta plugin utente) e può essere usato come preset o strumento CLI. Babili potrà inoltre implementare ottimizzazioni specifiche per ES2015+.

Pronuncia

Shell
# sounds like "bah billy" or "Babadi" (from DBZ)
say Babili

Babili significa Babilonia in accadico.

Se non ricordi il nome, puoi usare anche babel-minify (abbiamo aperto un issue per il nome).

Perché minificare?

A livello base, la minificazione rimuove caratteri non necessari da un programma senza alterarne la funzionalità – come commenti, spazi bianchi, ritorni a capo e parentesi ridondanti. La minificazione avanzata può trasformare i programmi in equivalenti più piccoli ed eliminare codice ridondante/inraggiungibile.

La minificazione è utile principalmente per ridurre le dimensioni del payload JavaScript inviato dal server al client: gli utenti scaricheranno meno codice per usare il tuo sito. La minificazione avanzata può inoltre ridurre i tempi di parsing (meno codice da analizzare) e in alcuni casi migliorare le performance runtime (es. ottimizzazioni avanzate come l'inlining di funzioni).

Minificatori attuali

Strumenti come Uglify attualmente non supportano il targeting delle ultime versioni di ECMAScript (non ancora: branch harmony).

Attualmente usiamo strumenti come Babel per compilare codice ES2015 in ES5 per supportare browser obsoleti. Poi usiamo strumenti come Uglify per ridurre le dimensioni del bundle.

Man mano che i browser implementano più funzionalità ES2015 e abbandoniamo il supporto per versioni obsolete, si crea una finestra mobile tra la versione ECMAScript in cui scriviamo e quella che minifichiamo. Tuttavia, poiché Uglify non può analizzare ES2015+, dovremmo comunque compilare verso ES5.

Babili

È qui che entra in gioco Babili.

Babili è compatibile con ES2015+ perché costruito sulla toolchain di Babel. È implementato come set di plugin Babel, utilizzabile tramite il preset babili.

Esempio

Supponiamo di targettizzare le ultime versioni di Chrome, Firefox, Edge e Safari – tutte supportano le classi ES2015. In questo caso, compilare classi ES2015 in funzioni costruttore e metodi prototipali (ES5) produrrebbe più codice (e potenzialmente annullerebbe ottimizzazioni specifiche per le classi nei browser).

JavaScript
class Mangler {
constructor(program) {
this.program = program;
}
}
// need this since otherwise Mangler isn't used
new Mangler();

Prima, avremmo potuto eseguire Babel per transpilare la classe in una funzione e poi eseguire Uglify sul codice compilato da inviare al browser.

JavaScript
// ES2015 code -> Babel -> Uglify/Babili -> Minified ES5 Code
var a=function a(b){_classCallCheck(this,a),this.program=b};a();

Con Babili, puoi semplicemente eseguire il minifier che funziona direttamente sul codice ES2015.

JavaScript
// ES2015 code -> Babili -> Minified ES2015 Code
class a{constructor(b){this.program=b}}new a;

È importante notare che questo non è specifico solo per ES2015. Dato che Babel si aggiorna insieme a ECMAScript (con ES2015, ES2016 e ora ES2017) e segue il processo di proposta per le funzionalità sperimentali (con i nostri preset stage-x), il minifier dovrebbe essere in grado di produrre qualsiasi versione di ECMAScript supportata.

In futuro, potremmo sfruttare le informazioni sulla sintassi ES2015+ disponibili al momento della compilazione (ad esempio sappiamo che una determinata funzione è un arrow function o che un binding ha scope di blocco) per ottimizzazioni avanzate. Potremo inoltre sfruttare creativamente la conoscenza dell'ambiente ES2015+ di destinazione.

Siamo solo all'inizio, quindi facci sapere se hai idee!

Alcuni dei Plugin

Per dare un'idea di alcune trasformazioni:

babel-plugin-minify-constant-folding:

Tenta di valutare le espressioni e incorporare il risultato. Per ora gestisce solo numeri e stringhe.

JavaScript
2 * 3;
"b" + a + "c" + "d" + g + z + "f" + "h" + "z"
JavaScript
6;
"b" + a + "cd" + g + z + "fhz";

babel-plugin-minify-mangle-names:

Ridenominazione di variabili consapevole del contesto e dello scope.

JavaScript
var globalVariableName = 42;
function foo() {
var longLocalVariableName = 1;
if (longLocalVariableName) {
console.log(longLocalVariableName);
}
}
JavaScript
var globalVariableName = 42;
function foo() {
var a = 1;
if (a) {
console.log(a);
}
}

Utilizzo

Preset Babel

Se usi già Babel, puoi semplicemente aggiungere il preset babili (babel-preset-babili) alla tua configurazione.

Ti consigliamo di abilitarlo solo in produzione, utilizzando l'opzione env che impiega process.env.BABEL_ENV o process.env.NODE_ENV

Shell
$ npm install babel-preset-babili --save-dev
JavaScript
// previous .babelrc
{ "presets": ["es2015"] }
// .babelrc
{
"presets": ["es2015"],
"env": {
"production": {
"presets": ["babili"]
}
}
}

Un problema dell'uso di Babili come preset è che verrebbe eseguito per singolo file anziché sull'intero bundle. La minificazione solitamente avviene dopo il bundling, come con "UglifyJsPlugin" in webpack. Tuttavia, eseguirlo dopo il bundling farebbe perdere i vantaggi di velocità (da misurare) della transpilazione e minificazione nello stesso passaggio. È un aspetto da valutare: come integrare o passare più informazioni al bundler.

CLI Babili

Se non usi Babel, puoi utilizzare il nostro strumento CLI standalone babili (attualmente è un wrapper per babel-cli + il preset). Puoi eseguirlo dopo la transpilazione (o meno) al posto di Uglify.

Shell
$ npm install babili --save-dev
Shell
$ babili src -d lib
# equivalent to
# babel src -d lib --presets=babili --no-babelrc

Webpack

Puoi usare il preset direttamente con babel-loader.

Shell
$ npm install babel-core babel-loader babel-preset-babili
JavaScript
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel',
query: {
presets: ['babili']
}
}
]
}

Oppure usarlo separatamente con babili-webpack-plugin (realizzato da @boopathi, che lavora anche su Babili).

Shell
$ npm install babili-webpack-plugin --save-dev
JavaScript
// webpack.config.js
const BabiliPlugin = require("babili-webpack-plugin");
module.exports = {
entry: //...,
output: //...,
plugins: [
new BabiliPlugin(options)
]
}

Vogliamo migliorare l'integrazione con Webpack/bundler nel prossimo futuro! Vedi anche #100.

Vantaggi/Svantaggi

Vantaggi di Uglify

  • Nessuna modifica alla toolchain esistente se stai già minificando.

  • Collaudato in produzione/pronto per l'uso (esiste da anni ed è ampiamente adottato - lo usiamo tutti)!

  • È estremamente veloce e produce già codice compatto.

Svantaggi di Uglify

  • Utilizza un parser e tooling personalizzato, quindi è difficile gestire output/minificazione ES2015+ e apportare modifiche.

  • Non modulare, attualmente non è possibile creare plugin personalizzati o strategie di minificazione al di fuori del core.

Vantaggi di Babili:

  • Consapevole di ES2015+ (non richiede accorgimenti speciali grazie al parser Babylon) e si aggiornerà automaticamente con gli standard/browser.

  • Utilizza la toolchain esistente di Babel, può essere usato come preset o strumento standalone.

  • Potenziale per trasformazioni avanzate personalizzate per React/Flow, ecc.

  • Potrebbe utilizzare annotazioni Flow/Typescript per abilitare minificazioni avanzate.

  • Ogni fase di minificazione è separata in plugin indipendenti, con ampie opzioni di personalizzazione. Questo facilita i contributi e la segnalazione di issue specifiche. Permette anche di creare plugin sperimentali prima di integrarli nel core.

  • Transizione semplice per chi già conosce la transpilazione con Babel.

Svantaggi di Babili:

  • Rilasciato precocemente, quindi pochi utenti attuali. I primi adottatori affronteranno uno strumento meno collaudato di Uglify.

  • Attualmente, prestazioni e dimensioni sono inferiori a Uglify nei benchmark. Miglioreremo questo aspetto.

TL;DR: Babili può seguire gli standard ECMAScript e supportare gli ambienti necessari. Ha grande potenziale: non è ancora maturo come Uglify, ma con ottimizzazioni e utenti diventerà competitivo.

Come Contribuire

Amjad lavorava al progetto da tempo, ma l'abbiamo rilasciato prima in beta per permettere alla community di testarlo e contribuire segnalando bug o patch.

È ancora un progetto giovane con molto spazio per contributi! La priorità è renderlo più stabile/robusto per il rilascio 1.0.0.

Lavoreremo per eguagliare velocità e compattezza di Uglify/Closure Compiler in modalità semplice.

  • Test su più codebase: Aiuterà tutti. Un minificatore elabora tutto il codice, quindi potrebbe emergere edge case non coperti dai test. La REPL supporta già il minificatore per riprodurre bug. In futuro aggiungeremo opzioni per abilitare plugin specifici.

  • Infrastruttura/manutenzione: Implementeremo benchmark robusti e test d'integrazione su progetti open-source popolari (minificare ed eseguire i loro test).

  • Verificare l'output: Se qualcosa può essere semplificato, è semplice segnalare un'issue o suggerire nuove trasformazioni. Essendo modulare, chiunque può creare plugin personalizzati prima di integrarli nel core.

Un enorme ringraziamento ad Amjad (@amasad) per aver avviato questo progetto e a Facebook per averci permesso di rilasciarlo sotto l'organizzazione Babel come progetto con licenza MIT! Sebastian (@kittens) è stato ovviamente una parte fondamentale di tutto ciò, dato che senza Babel non sarebbe stato possibile. Ringraziamo anche James (@thejameskyle) e Juriy (@kangax) per aver contribuito a portare a termine il rilascio! Vorremmo inoltre ringraziare Boopathi (@boopathi) che abbiamo invitato ad aiutarci dopo aver visto il lavoro sul suo progetto babel-minify!