7.10.0 publiée : Champs de classe dans preset-env, vérifications '#private in' et meilleur tree-shaking React
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 →
Nous venons de publier une nouvelle version mineure de Babel !
Cette version 7.10 inclut :
-
Support complet de la nouvelle proposition Stage 1 : vérifications
#prop in objpour les champs privés proposition. -
@babel/preset-envcompile désormais les échappements Unicode au format ES2015 (\u{Babe1}) vers la syntaxe legacy équivalente (\uDAAA\uDFE1). -
Deux améliorations de l'opérateur Optional Chaining (
?.) -
Support du parser pour la nouvelle proposition Stage 1 Module Attributes (
import a from "./a.json" with type: "json"). -
Meilleur support du tree-shaking pour le code React (ex:
React.memo) ! -
Création du dépôt RFCs et des pages GitHub Discussions !
Vous pouvez consulter le changelog complet sur GitHub.
Parallèlement à cette version de Babel, nous publions la première version expérimentale de notre nouvelle architecture de compatibilité pour polyfills (voir ci-dessous pour plus de détails), grâce à Nicolò et à d'incroyables contributeurs ! Nous avons initié ces discussions il y a plus d'un an via une issue RFC dans le dépôt Babel.
Par ailleurs, nous disposons désormais d'un processus RFC officiel pour discuter des changements impactant significativement nos utilisateurs : consultez-le dans le dépôt babel/rfcs ! Nous avons également activé les GitHub Discussions sur notre dépôt pour vos retours et questions !
Si vous ou votre entreprise souhaitez soutenir Babel et l'évolution de JavaScript sans savoir comment procéder, vous pouvez nous faire un don via notre Open Collective ou mieux encore, collaborer directement avec nous à l'implémentation de nouvelles propositions ECMAScript ! Projet reposant sur le bénévolat, nous comptons sur le soutien communautaire pour financer nos efforts au service de la diversité des utilisateurs JavaScript. Contactez-nous à team@babeljs.io pour en discuter !
Nouvelles fonctionnalités activées par défaut
Parsing de import.meta
Maintenant qu'elle a atteint le Stage 4, le parsing de import.meta est activé par défaut, grâce à Kiko. Notez que @babel/preset-env ne prend pas en charge par défaut sa transformation, car le contenu de cet objet dépend du moteur d'exécution et n'est pas défini dans la spécification ECMAScript.
console.log(import.meta); // { url: "file:///home/user/my-module.js" }
Transforming ​u{...}-style Unicode escapes (#11377)
Nous avons également constaté l'absence de support pour une fonctionnalité ECMAScript vieille de 5 ans : les échappements Unicode au format \u{...} ! Grâce à Justin, @babel/preset-env peut désormais les compiler dans les chaînes et identifiants par défaut.
var \u{1d49c} = "\u{Babe1}";
console.log(\u{1d49c});
var _ud835_udc9c = "\uDAAA\uDFE1";
console.log(_ud835_udc9c);
Ajout des propriétés de classe et méthodes privées à l'option shippedProposals de @babel/preset-env (#11451)
Enfin, grâce à Jùnliàng, nous avons ajouté @babel/plugin-proposal-class-properties et @babel/plugin-proposal-private-methods à l'option shippedProposals de @babel/preset-env. Ces propositions ne sont pas encore au Stage 4 (c'est-à-dire intégrées au standard ECMAScript), mais elles sont déjà activées par défaut dans de nombreux moteurs JavaScript.
Si vous n'êtes pas familier avec :
class Bork {
// Public Fields
instanceProperty = "bork";
static staticProperty = "babelIsCool";
// Private Fields
#xValue = 0;
a() {
this.#xValue++;
}
// Private methods
get #x() { return this.#xValue; }
set #x(value) {
this.#xValue = value;
}
#clicked() {
this.#x++;
}
}
Si vous l'avez manqué dans la dernière version, la 7.9 a introduit une nouvelle option : "bugfixes": true qui peut considérablement réduire votre code généré.
{
"presets": [
["@babel/preset-env", {
"targets": { "esmodules": true }, // Use the targets that you was already using
"bugfixes": true // will be default in Babel 8
}]
]
}
Améliorations ergonomiques pour le chaînage optionnel ?. (#10961, #11248)
Dans TypeScript 3.9, l'interaction entre les assertions de non-nullité (postfixe !) et le chaînage optionnel a été modifiée pour la rendre plus utile.
foo?.bar!.baz
Dans TypeScript 3.8 et Babel 7.9, le code ci-dessus était interprété comme (foo?.bar)!.baz : "Si foo n'est pas nul, récupère .bar puis fais confiance que foo?.bar n'est jamais nul pour toujours récupérer .bar". Cela signifie que lorsque foo est nul, ce code lance toujours une erreur car on tente d'accéder à .baz sur undefined.
Dans TypeScript 3.9 et Babel 7.10, le code se comporte désormais comme foo?.bar.baz : "Si foo n'est pas nul, récupère .bar.baz et fais-moi confiance que foo?.bar n'est pas nul". Merci à Bruno pour son aide à l'implémentation !
De plus, la proposition des champs de classe a récemment ajouté la prise en charge du chaînage optionnel ?. avec les champs privés. Le code suivant est donc désormais valide :
obj?.property.#priv;
obj?.#priv;
Notez que dans le deuxième exemple, si obj n'est pas nul mais ne possède pas le champ #priv, une erreur sera tout de même levée (exactement comme obj.#priv le ferait). La section suivante explique comment l'éviter !
Vérification de champs privés via in (#11372)
class Person {
#name;
hug(other) {
if (#name in other) console.log(`${this.#name} 🤗 ${other.#name}`);
else console.log("It's not a person!")
}
}
Cette proposition de Stage 1 permet de vérifier statiquement si un objet possède un champ privé spécifique.
Les champs privés intègrent une "vérification de marque" : si vous tentez d'y accéder dans un objet où ils ne sont pas définis, une exception est levée. Bien qu'il soit possible de déterminer la présence d'un champ privé via un bloc try/catch, cette proposition offre une syntaxe plus concise et robuste.
Vous pouvez en savoir plus dans la description de la proposition et tester cette fonctionnalité en installant le plugin @babel/plugin-proposal-private-property-in-object puis en l'ajoutant à votre configuration Babel. Merci à Justin pour cette contribution !
Prise en charge de l'analyse syntaxique des attributs de modules (#10962)
La proposition d'attributs de modules (Stage 1) permet de fournir au moteur, au chargeur de modules ou au bundler des informations supplémentaires sur le fichier importé. Par exemple, vous pouvez explicitement spécifier qu'il doit être analysé comme du JSON :
import metadata from "./package.json" with type: "json";
Ces attributs peuvent également être utilisés avec import() dynamique. Notez la prise en charge des virgules finales pour faciliter l'ajout ou la suppression du second paramètre !
const metadata = await import(
"./package.json",
{ with: { type: "json" } },
);
Grâce à Vivek, Babel prend désormais en charge l'analyse syntaxique de ces attributs : vous pouvez ajouter le plugin @babel/plugin-syntax-module-attributes à votre configuration Babel ou, si vous utilisez @babel/parser directement, activer le plugin moduleAttributes. Actuellement, nous n'acceptons que l'attribut type, mais nous pourrions assouplir cette restriction à l'avenir selon l'évolution de la proposition.
Babel ne transforme pas ces attributs, qui doivent être gérés directement par votre bundler ou un plugin personnalisé. Actuellement, les transformateurs de modules Babel ignorent ces attributs. Nous discutons de la possibilité de les transmettre à l'avenir.
Meilleur tree-shaking pour les composants React (#11428)
React expose de nombreuses fonctions pures utilisées pour annoter ou encapsuler des éléments, comme React.forwardRef, React.memo ou React.lazy. Cependant, les minifiers et bundlers ne savent pas que ces fonctions sont pures et ne peuvent donc pas les supprimer.
Grâce à Devon de l'équipe Parcel, @babel/preset-react injecte désormais des annotations /*#__PURE__*/ sur ces appels de fonctions pour indiquer qu'elles peuvent être éliminées par le tree-shaking. Nous n'avions auparavant appliqué cette technique qu'au JSX lui-même (<a></a> => /*#__PURE__*/React.createElement("a", null))
import React from 'react';
const SomeComponent = React.lazy(() => import('./SomeComponent'));
import React from 'react';
const SomeComponent = /*#__PURE__*/React.lazy(() => import('./SomeComponent'));
Nouvelle architecture expérimentale de polyfills (#10008, babel-polyfills)
Ces trois dernières années, @babel/preset-env a aidé les utilisateurs à réduire la taille des bundles en ne transpilant que les fonctionnalités syntaxiques et en incluant uniquement les polyfills core-js nécessaires pour leurs environnements cibles.
Actuellement, Babel propose trois méthodes différentes pour injecter des polyfills core-js dans le code source :
-
En utilisant l'option
useBuiltIns: "entry"de@babel/preset-env, il est possible d'injecter des polyfills pour chaque fonctionnalité ECMAScript non prise en charge nativement par les navigateurs cibles ; -
Avec
useBuiltIns: "usage", Babel n'injecte que les polyfills pour les fonctionnalités ECMAScript non prises en charge, mais uniquement si elles sont effectivement utilisées dans le code source d'entrée ; -
En utilisant
@babel/plugin-transform-runtime, Babel injecte des ponyfills (qui sont "purs" et ne polluent pas la portée globale) pour chaque fonctionnalité ECMAScript utilisée et supportée parcore-js. Cette approche est généralement utilisée par les auteurs de bibliothèques.
Notre position dans l'écosystème JavaScript nous permet de pousser ces optimisations encore plus loin. @babel/plugin-transform-runtime présente des avantages significatifs pour certains utilisateurs par rapport à useBuiltIns, mais il ne prend pas en compte les environnements cibles : nous sommes en 2020 et très peu de personnes ont probablement besoin de charger un polyfill pour Array.prototype.forEach.
De plus, pourquoi devrions-nous limiter la capacité d'injection automatique des polyfills nécessaires uniquement à core-js ? Il existe également des polyfills pour le DOM, pour Intl, et pour une myriade d'autres API de la plateforme web. Tout le monde n'utilise pas core-js ; il existe de nombreux autres polyfills ECMAScript valides avec des compromis différents (par exemple taille du code source vs conformité aux spécifications), et les utilisateurs devraient pouvoir choisir leur polyfill. Par exemple, nous travaillons activement à une intégration avec es-shims.
Et si la logique d'injection n'était pas liée aux données réelles sur les polyfills disponibles ou nécessaires, pour qu'ils puissent être utilisés et développés indépendamment ?
Nous publions aujourd'hui la première version expérimentale de quatre nouveaux packages :
-
babel-plugin-polyfill-corejs2(obsolète)
Ces packages prennent tous en charge une option method pour ajuster leur mode d'injection (analogue à ce qu'offrent actuellement @babel/preset-env et @babel/plugin-transform-runtime). Vous pouvez injecter un polyfill dans un point d'entrée (portée globale uniquement) ou par utilisation directe dans votre code (options de portée globale et "pure"). Vous trouverez ci-dessous un CodeSandbox personnalisé pour tester les différences entre les options de polyfill.
Nous publions également @babel/helper-define-polyfill-provider : un nouveau package d'aide permettant aux auteurs et utilisateurs de polyfills de définir leurs propres plugins de fourniture de polyfills.
Un grand merci à Jordan pour sa collaboration avec Nicolò qui a permis de construire le plugin es-shims !
Pour en savoir plus sur ces packages et apprendre à les configurer, consultez le README du projet.
Ces packages sont encore expérimentaux. Nous apprécierions vos retours sur Twitter ou GitHub, mais ils ne sont pas encore prêts pour la production. Par exemple, nous devons encore intégrer certains polyfills et nous n'avons pas testé les plugins dans des applications de production.
