Vai al contenuto principale

Rilasciata la versione 5.0.0

· 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 →

Negli ultimi mesi Babel è stato accolto in diverse grandi community come Node, React, Ember, Backbone, Angular, Rails e molte altre. Abbiamo lanciato la pagina Utenti solo poche settimane fa ed è fantastico vedere tutti coloro che lo stanno utilizzando. Aziende come CloudFlare, Netflix, Mozilla e Yahoo!. Progetti come Ghost, Atom, Mapbox e molti altri ancora.

Abbiamo visto tantissimi post di blog, talk, eventi e corsi incentrati su ES6+ con Babel, e gli strumenti ufficiali di Babel sono stati scaricati quasi 2 milioni di volte.

Oggi rilasciamo di gran lunga la versione più importante di Babel di sempre.

Se stai effettuando l'aggiornamento da Babel 4.x consulta le modifiche incompatibili.

Questa release include le nuove proposte per ES7:

L'intera pipeline interna di attraversamento e trasformazione è stata riscritta, migliorando sostanzialmente la flessibilità e consentendo future ottimizzazioni delle prestazioni.

Questa release introduce anche un'API per i plugin, che permette agli utenti di integrare trasformatori personalizzati per sfruttare i potenti meccanismi di trasformazione offerti da Babel.

Puoi consultare il CHANGELOG completo qui.

E come al solito se riscontri regressioni segnalale immediatamente.

Processo TC39

In questa release inizierai a vederci allineati al processo TC39. Il TC39 è il comitato tecnico di ECMA che redige lo standard ECMAScript. Il loro processo è suddiviso in 5 fasi:

  • Stage 0 - Bozza iniziale

  • Stage 1 - Proposta

  • Stage 2 - Bozza

  • Stage 3 - Candidato

  • Stage 4 - Concluso

Le proposte di stage 2 o superiore sono abilitate in Babel per impostazione predefinita. Ciò non significa che siano garantite per l'inclusione nelle future specifiche ECMAScript o nello stesso Babel. Lo stage 2 è considerato un buon punto per l'inclusione predefinita in Babel grazie alla relativa maturità e alla necessità di feedback critici sulle proposte.

Ora approfondiamo i cambiamenti apportati nella 5.0.


Indice:

New Features

Nuove Proposte

Stage 0: Proprietà delle Classi

La proposta di stage 0 sugli inizializzatori delle proprietà delle classi di Jeff Morrison colma la lacuna della composizione delle proprietà nelle classi. Queste sono analoghe agli esempi di proprietà delle classi elencati nell'annuncio beta di React 0.13.

Esempio:

JavaScript
class Person {
firstName = "Sebastian";
static lastName = "McKenzie";
}

assert(new Person().firstName, "Sebastian");
assert(Person.lastName, "McKenzie");

Utilizzo:

JavaScript
require("babel").transform("code", {
optional: ["es7.classProperties"]
});
// or
require("babel").transform("code", { stage: 0 });
Shell
$ babel --optional es7.classProperties script.js
# or
$ babel --stage 0 script.js

Stage 1: Decoratori

La proposta di stage 1 sui decoratori di Yehuda Katz consente di comporre elegantemente descrittori di proprietà e decoratori di metadati. In futuro ciò permetterà di rappresentare facilmente il potente Ember Object Model con classi native.

Esempio:

JavaScript
function concat(...args) {
let sep = args.pop();

return function(target, key, descriptor) {
descriptor.initializer = function() {
return args.map(arg => this[arg]).join(sep);
}
}
}

function autobind(target, key, descriptor) {
var fn = descriptor.value;
delete descriptor.value;
delete descriptor.writable;
descriptor.get = function () {
var bound = fn.bind(this);
Object.defineProperty(this, key, {
configurable: true,
writable: true,
value: bound
});
return bound;
};
}

class Person {
firstName = "Sebastian";
lastName = "McKenzie";

@concat("firstName", "lastName", " ") fullName;
@concat("lastName", "firstName", ", ") formalName;

@autobind
getFullName() {
return `${this.firstName} ${this.lastName}`;
}
}

assert(new Person().fullName, "Sebastian McKenzie");
assert(new Person().formalName, "McKenzie, Sebastian");
assert(new Person().getFullName.call(null), "Sebastian McKenzie");

Utilizzo:

JavaScript
require("babel").transform("code", {
optional: ["es7.decorators"]
});
// or
require("babel").transform("code", { stage: 1 });
Shell
$ babel --optional es7.decorators script.js
# or
$ babel --stage 1 script.js

Stage 1: Estensioni di Export

La proposta di stage 1 sulle istruzioni aggiuntive di export-from di Lee Byron completa la simmetria tra le istruzioni import ed export, consentendo di esportare facilmente namespace e default da moduli esterni senza modificare l'ambito locale.

Esportare un default

JavaScript
export foo from "bar";

equivalente a:

JavaScript
import _foo from "bar";
export { _foo as foo };

Esportare un namespace

JavaScript
export * as ns from "mod";

equivalente a:

JavaScript
import * as _ns from "mod";
export { _ns as ns };

Utilizzo:

JavaScript
require("babel").transform("code", {
optional: ["es7.exportExtensions"]
});
// or
require("babel").transform("code", { stage: 1 });
Shell
$ babel --optional es7.exportExtensions script.js
# or
$ babel --stage 1 script.js

Ottimizzazioni per React

In preparazione per React 0.14, Babel supporta alcuni trasformatori di ottimizzazione per JSX.

Elementi Costanti

A partire dalla versione 0.14, gli ReactElement e i loro oggetti props possono essere trattati come tipi di valore, cioè qualsiasi istanza è concettualmente equivalente se tutti i loro valori sono identici.

Prendiamo ad esempio questa funzione:

JavaScript
import React from "react";

function render() {
return <div className="foo" />;
}

Questo può essere ottimizzato spostando il JSX fuori dal corpo della funzione in modo che ogni volta che viene chiamata, venga restituita la stessa istanza:

JavaScript
import React from "react";

var _ref = <div className="foo" />;

function render() {
return _ref;
}

Non solo ci permette di riutilizzare gli stessi oggetti, ma React interromperà automaticamente qualsiasi riconciliazione di componenti costanti - senza un shouldComponentUpdate manuale.

Utilizzo:

JavaScript
require("babel").transform("code", {
optional: ["optimisation.react.constantElements"]
});
Shell
$ babel --optional optimisation.react.constantElements script.js

Elementi Inline

Solo produzione

Gli elementi inline dovrebbero essere abilitati only in produzione poiché vengono soppressi messaggi di warning di React, il che è estremamente rischioso in sviluppo.

A partire da React 0.14, gli ReactElement possono essere inlinati:

JavaScript
<div className="foo">{bar}<Baz key="baz" /></div>

come oggetti:

JavaScript
{ type: 'div', props: { className: 'foo', children:
[ bar, { type: Baz, props: { }, key: 'baz', ref: null } ]
}, key: null, ref: null }

Questo migliora le prestazioni rispetto alla chiamata React.createElement esistente inlinandone il risultato.

Utilizzo:

JavaScript
require("babel").transform("code", {
optional: ["optimisation.react.inlineElements"]
});
Shell
$ babel --optional optimisation.react.inlineElements script.js

.babelrc

Babel 5.0.0 offre supporto nativo per .babelrc in tutte le sue integrazioni. Ciò significa che funzionerà con babel/register, babel-node e con tutta la gamma di plugin per sistemi di build e module loader come babel-loader, babelify, e altri.

.babelrc è l'equivalente di .jshintrc per JSHint e .jscsrc per JSCS.

JSON
{
"stage": 1,
"ignore": [
"foo.js",
"bar/**/*.js"
]
}

Consulta la documentazione per maggiori informazioni.

Plugin API

La versione 5.0.0 introduce anche l'attesa API per i plugin. Questo ti permette di integrare le potenti funzionalità interne di traversamento e trasformazione di Babel. Vedi la documentazione per maggiori dettagli.

Breaking Changes

Opzione Sperimentale Rimossa

L'opzione experimental è stata rimossa. Non temere però: esiste un sostituto. Babel ora categorizza i transformer ES7 per stage TC39.

tl;dr Se stavi usando l'opzione experimental, sostituisci semplicemente con $ babel --stage 0 o { stage: 0 }.

Promemoria: Le proposte di stage 2 o superiore sono abilitate di default.

Stage 0

  • es7.classProperties

  • es7.comprehensions

Stage 1

  • es7.asyncFunctions

  • es7.decorators

  • es7.exportExtensions

  • es7.objectRestSpread

Stage 2 (abilitati di default)

  • es7.exponentiationOperator

Per la lista completa delle proposte ES7 attuali, consulta il repository tc39/ecma262.

Opzione returnUsedHelpers rinominata

L'opzione returnUsedHelpers è stata rinominata in metadataUsedHelpers e il risultato restituito è stato modificato da usedHelpers a metadata.usedHelpers.

Modifiche alle Classi

La versione 5.0.0 introduce alcune aggiornate semantiche per le classi derivate attese da tempo.

super() deve essere chiamato nel costruttore di una classe derivata.

JavaScript
class Foo extends Bar {
constructor() {
// no `super();`
}
}

L'accesso a this prima di super() nel costruttore di una classe derivata non è consentito.

JavaScript
class Foo extends Bar {
constructor() {
this.foo; // `this` access before `super();`
super();
}
}

super() è consentito solo nei costruttori delle classi derivate.

JavaScript
class Foo {
constructor() {
super(); // not in a derived constructor
}
}

Funzionalità Rimosse

  • Il playground è stato rimosso per concentrare lo sviluppo sulle funzionalità ES principali e sulle proposte. Ciò riduce anche il rischio di conflitti sintattici che potrebbero impedire l'implementazione di funzionalità ufficiali.

  • I riferimenti astratti sono stati rimossi poiché la proposta è stata sostituita. Il supporto per una o più delle proposte sostitutive potrebbe essere implementato in futuro.


In conclusione, speriamo che tu sia entusiasta di questo rilascio quanto noi. C'è molto lavoro dietro, e crediamo che ci preparerà al meglio per il futuro.

— The Babel team

Gli import sono ora hoisted

Nella versione 4.x, gli import venivano inseriti inline dove comparivano nel codice. Ciò significa che questo codice:

global.test = 'test'
import './test'

verrebbe compilato in:

'use strict';

global.test = 'test';
require('./test');

Tuttavia, a partire dalla versione 5.x, questo comportamento è stato modificato per conformarsi alla specifica ES6 e le importazioni saranno ora hoistate. Ciò significa che nel codice pratico lo snippet sopra verrà convertito in qualcosa come:

'use strict';

require('./test');
global.test = 'test';

Se il tuo codice richiedeva che determinati elementi venissero eseguiti durante l'importazione di un modulo specifico -come potrebbe accadere durante il testing quando è necessario simulare proprietà di window :)- potresti estrarre quella logica in un file separato e importarlo prima del codice che ne necessita.