Version 5.0.0 publiée
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 →
Ces derniers mois, Babel a été adopté par plusieurs grandes communautés comme Node, React, Ember, Backbone, Angular, Rails et bien d'autres. Nous avons lancé la page Utilisateurs il y a seulement quelques semaines, et c'est vraiment impressionnant de voir tous ceux qui l'utilisent. Des entreprises comme CloudFlare, Netflix, Mozilla et Yahoo!. Des projets comme Ghost, Atom, Mapbox, et bien d'autres encore.
Nous avons vu d'innombrables articles de blog, conférences, événements et cours sur ES6+ utilisant Babel, et les outils officiels de Babel ont été téléchargés près de 2 millions de fois.
Aujourd'hui, nous publions de loin la plus grande version de Babel jamais réalisée.
Si vous effectuez une mise à jour depuis Babel 4.x, veuillez consulter les changements cassants.
Cette version inclut les nouvelles propositions ES7 :
L'ensemble du pipeline interne de traversée et de transformation a été réécrit, ce qui améliore considérablement la flexibilité et permettra de nombreuses optimisations futures des performances du pipeline.
Cette version introduit également une API de plugin, permettant aux utilisateurs d'intégrer leurs propres transformateurs personnalisés pour exploiter les puissants mécanismes de transformation offerts par Babel.
Vous pouvez consulter le CHANGELOG complet ici.
Et comme toujours, si vous rencontrez des régressions, merci de les signaler immédiatement.
Processus TC39
Dans cette version, vous constaterez notre alignement avec le processus TC39. Le TC39 est le comité technique d'ECMA chargé de rédiger le standard ECMAScript. Leur processus est catégorisé en 5 étapes :
-
Étape 0 - Ébauche préliminaire (Strawman)
-
Étape 1 - Proposition
-
Étape 2 - Brouillon
-
Étape 3 - Candidat
-
Étape 4 - Finalisée
Les propositions de l'étape 2 ou supérieure sont activées par défaut dans Babel. Cela ne signifie pas qu'elles seront nécessairement incluses dans les futures spécifications ECMAScript ou même dans Babel lui-même. L'étape 2 est considérée comme un bon point pour l'inclusion par défaut dans Babel en raison de leur maturité relative et du besoin de retours critiques sur les propositions.
Plongeons maintenant dans les changements apportés à la version 5.0.
Sommaire :
New Features
Nouvelles propositions
Stage 0 : Class Properties
La proposition stage 0 de Jeff Morrison sur les initialiseurs de propriétés de classe comble le manque de composition de propriétés dans les classes. Cela correspond à l'exemple des propriétés de classe mentionné dans l'annonce de React 0.13 beta.
Exemple :
class Person {
firstName = "Sebastian";
static lastName = "McKenzie";
}
assert(new Person().firstName, "Sebastian");
assert(Person.lastName, "McKenzie");
Utilisation :
require("babel").transform("code", {
optional: ["es7.classProperties"]
});
// or
require("babel").transform("code", { stage: 0 });
$ babel --optional es7.classProperties script.js
# or
$ babel --stage 0 script.js
Stage 1 : Decorators
La proposition stage 1 de Yehuda Katz sur les décorateurs permet de composer élégamment des descripteurs de propriétés et des métadonnées décoratives. À terme, cela permettra de représenter facilement le puissant modèle objet d'Ember avec des classes natives.
Exemple :
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");
Utilisation :
require("babel").transform("code", {
optional: ["es7.decorators"]
});
// or
require("babel").transform("code", { stage: 1 });
$ babel --optional es7.decorators script.js
# or
$ babel --stage 1 script.js
Stage 1 : Export Extensions
La proposition stage 1 de Lee Byron sur les instructions d'exportation supplémentaires achève la symétrie entre les instructions import et export, vous permettant d'exporter facilement des espaces de noms et des exports par défaut depuis des modules externes sans modifier la portée locale.
Exporter un default
export foo from "bar";
équivalent à :
import _foo from "bar";
export { _foo as foo };
Exporter un namespace
export * as ns from "mod";
équivalent à :
import * as _ns from "mod";
export { _ns as ns };
Utilisation :
require("babel").transform("code", {
optional: ["es7.exportExtensions"]
});
// or
require("babel").transform("code", { stage: 1 });
$ babel --optional es7.exportExtensions script.js
# or
$ babel --stage 1 script.js
Optimisations React
En préparation de React 0.14, Babel prend en charge certains transformateurs d'optimisation pour JSX.
Éléments constants
À partir de la version 0.14, les ReactElements et leurs objets props peuvent être traités comme des types valeur. C'est-à-dire que toute instance est conceptuellement équivalente si toutes leurs valeurs sont identiques.
Prenons cet exemple de fonction :
import React from "react";
function render() {
return <div className="foo" />;
}
On peut l'optimiser en déplaçant le JSX hors du corps de la fonction, afin que la même instance soit retournée à chaque appel :
import React from "react";
var _ref = <div className="foo" />;
function render() {
return _ref;
}
Cela permet non seulement de réutiliser les mêmes objets, mais React interrompra automatiquement
toute réconciliation des composants constants - sans shouldComponentUpdate manuel.
Utilisation :
require("babel").transform("code", {
optional: ["optimisation.react.constantElements"]
});
$ babel --optional optimisation.react.constantElements script.js
Éléments inline
Les éléments inline doivent only être activés en production car plusieurs messages d'avertissement React sont supprimés, ce qui est très risqué en développement.
À partir de React 0.14, les ReactElements peuvent être inlinés :
<div className="foo">{bar}<Baz key="baz" /></div>
sous forme d'objets :
{ type: 'div', props: { className: 'foo', children:
[ bar, { type: Baz, props: { }, key: 'baz', ref: null } ]
}, key: null, ref: null }
Cela améliore les performances par rapport à l'appel existant React.createElement
en inlinant son résultat.
Utilisation :
require("babel").transform("code", {
optional: ["optimisation.react.inlineElements"]
});
$ babel --optional optimisation.react.inlineElements script.js
.babelrc
Babel 5.0.0 prend désormais en charge .babelrc nativement dans l'ensemble de ses intégrations. Cela signifie qu'il fonctionnera avec babel/register, babel-node ainsi qu'avec toute la gamme de plugins de build systems et de module loaders comme babel-loader, babelify, et autres.
.babelrc est l'équivalent de .jshintrc pour JSHint et .jscsrc pour JSCS.
{
"stage": 1,
"ignore": [
"foo.js",
"bar/**/*.js"
]
}
Consultez la documentation pour plus d'informations.
API de plugins
La version 5.0.0 introduit également l'API de plugins tant attendue. Elle vous permet d'interagir avec les puissants mécanismes internes de traversée et transformation de Babel. Voir la documentation pour plus d'informations.
Breaking Changes
Option expérimentale
L'option experimental a été supprimée. Pas d'inquiétude cependant : un remplacement existe. Babel classe désormais les transformateurs ES7 selon les stades TC39.
En bref : si vous utilisiez l'option experimental, remplacez-la simplement par $ babel --stage 0 ou { stage: 0 }.
Rappel : Les propositions de stade 2 ou supérieur sont activées par défaut.
Stade 0
-
es7.classProperties -
es7.comprehensions
Stade 1
-
es7.asyncFunctions -
es7.decorators -
es7.exportExtensions -
es7.objectRestSpread
Stade 2 (activé par défaut, comme les stades supérieurs)
es7.exponentiationOperator
Pour la liste complète des propositions ES7 actuelles, consultez le dépôt tc39/ecma262.
Option returnUsedHelpers
L'option returnUsedHelpers a été renommée en metadataUsedHelpers et le résultat retourné a été modifié de usedHelpers à metadata.usedHelpers.
Changements relatifs aux classes
La version 5.0.0 introduit des sémantiques mises à jour pour les classes dérivées, attendues depuis longtemps.
super() doit être appelé dans le constructeur d'une classe dérivée.
class Foo extends Bar {
constructor() {
// no `super();`
}
}
L'accès à this avant super() dans un constructeur de classe dérivée est interdit.
class Foo extends Bar {
constructor() {
this.foo; // `this` access before `super();`
super();
}
}
super() est uniquement autorisé dans les constructeurs de classes dérivées.
class Foo {
constructor() {
super(); // not in a derived constructor
}
}
Fonctionnalités supprimées
-
Le playground a été retiré pour concentrer le développement sur les fonctionnalités ES principales et les propositions officielles. Cela réduit aussi les risques de conflits syntaxiques empêchant l'implémentation de fonctionnalités standards.
-
Les références abstraites ont été supprimées car la proposition a été remplacée. Le support d'une ou plusieurs des nouvelles propositions pourrait être implémenté à l'avenir.
Pour conclure, nous espérons que cette version vous enthousiasme autant que nous. Beaucoup d'efforts y ont été consacrés, et nous croyons qu'elle nous positionne durablement pour l'avenir.
— The Babel team
Les imports sont désormais hoistés
Dans la version 4.x, les imports étaient placés à l'endroit où ils apparaissaient dans le code. Ce qui signifie que ce code :
global.test = 'test'
import './test'
serait compilé en :
'use strict';
global.test = 'test';
require('./test');
Cependant, à partir de la version 5.x, ce comportement a été modifié afin de se conformer à la spécification ES6 et les importations seront désormais hoistées. Concrètement, cela signifie que l'extrait de code ci-dessus sera transformé en quelque chose comme :
'use strict';
require('./test');
global.test = 'test';
Si votre code nécessitait l'exécution de certaines opérations pendant l'importation d'un module spécifique - ce qui pourrait être le cas lors de tests où vous devez simuler des propriétés de window :) - vous devriez extraire ces opérations dans un fichier dédié et l'importer avant le code qui en dépend.