7.4.0 Publicado: core-js 3, métodos privados estáticos y aplicación parcial
Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →
¡Hoy publicamos Babel 7.4.0!
Esta versión incluye soporte para TypeScript 3.4, la propuesta de aplicación parcial en llamadas a funciones y métodos privados estáticos.
Hemos añadido soporte para expresiones entre paréntesis significativas en @babel/parser, ¡y además lo hemos hecho más compatible con la especificación que nunca!
Por último pero no menos importante, tanto @babel/preset-env como @babel/transform-runtime ahora soportan core-js@3, ¡y @babel/template tiene una nueva y dulce sintaxis!
Puedes leer el changelog completo en GitHub.
Un agradecimiento especial a todos los nuevos contribuidores de Babel 😊. Desde que empezamos a generar los changelogs de versiones usando GitHub Actions no habíamos tenido la oportunidad de agradecerles en cada lanzamiento, ¡pero desde Babel 7.3.3 ha habido mucha gente!
-
Babel 7.3.3: @Alec321, @mhcgrq, @ilyalesik, @yifei-fu
-
Babel 7.3.4: @elevatebart, @ian, @imjacobclark, @irohitb
-
Babel 7.4.0: @AmirS, @agoldis, @byara, @echenley, @tanohzana, @matt, @penielse, @pnowak
Muchas características de esta versión se han desarrollado en colaboración con nuestros patrocinadores. Bloomberg ha contribuido con soporte para un nuevo tipo de elemento privado en cada lanzamiento desde la 7.0 (7.1, 7.2, 7.3), ¡y ahora han implementado métodos privados estáticos! Solo quedan pendientes los getters y setters privados estáticos.
De manera similar, Trivago (un patrocinador de Base Support en OpenCollective) se encargó de la implementación del plugin de aplicación parcial.
Durante el último mes, hemos estado experimentando con trabajar de forma más directa con empresas en varias características/optimizaciones que beneficiarían a la comunidad: RunKit ha estado patrocinando a Nicolò para implementar soporte de placeholders en @babel/template.
Cuando gestionas un gran proyecto de código abierto, no todo es código: necesitamos administrar servidores, integración continua, cuentas de redes sociales y... ¡muchas contraseñas! Realmente agradecemos a 1Password por aceptarnos en su programa de soporte para open source y proporcionarnos una cuenta gratuita de 1Password Teams.
Si tú o tu empresa quieren apoyar a Babel y la evolución de JavaScript pero no están seguros de cómo, pueden donar a través de OpenCollective o, mejor aún, trabajar directamente con nosotros en la implementación de nuevas propuestas de ECMAScript. Como proyecto impulsado por voluntarios, dependemos del apoyo de la comunidad para financiar nuestros esfuerzos y mantener el código. ¡Contáctate con Henry en henry@babeljs.io si quieres conversar más!
core-js 3 (#7646)
Hemos recibido muchos elogios por nuestro trabajo en @babel/preset-env, pero gran parte de ese crédito realmente corresponde al increíble trabajo de Denis. Él mantiene core-js, que proporciona todos los polyfills cargados por @babel/polyfill, @babel/runtime y @babel/preset-env.
Acabamos de lanzar core-js@3, que incluye muchas características nuevas: puedes leer sobre ellas en "core-js@3, babel and a look into the future". Además de todas las nuevas propuestas, ahora es posible aplicar polyfills a métodos de instancia usando @babel/plugin-transform-runtime, permitiendo su uso en navegadores antiguos sin contaminar el entorno global:
// 'foo' could be either a string or an array, or a custom object
foo.includes("a");
// ⮕
import _includesInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/includes";
_includesInstanceProperty(foo).call(foo, "a");
@babel/preset-env y @babel/plugin-transform-runtime ahora admiten polyfills para propuestas: solo necesitas usar corejs: { version: 3, proposals: true } en lugar de corejs: 3 en tu configuración. ¡Recuerda que las propuestas de ECMAScript son inherentemente inestables y podrían cambiar en core-js@4!
Anteriormente, @babel/preset-env dependía completamente de datos de compat-table para determinar qué polyfills cargar para un entorno específico. core-js@3 introduce su propio conjunto de datos de compatibilidad con una suite de pruebas exhaustiva que debería proporcionar polyfills mucho más precisos.
Migración desde core-js@2
Dado que las versiones 2 y 3 de core-js son incompatibles entre sí (¡no queremos romper tu código!), la versión 3 no está habilitada por defecto.
-
If you are using
@babel/preset-env, you need to enable thecorejs: 3option:JavaScriptpresets: [
["@babel/preset-env", {
useBuiltIns: "usage", // or "entry"
corejs: 3,
}]
]Don't forget to update your installed version of
core-js!npm install --save core-js@3When using
core-js3, theuseBuiltIns: "entry"option not only transformsimport "core-js"imports, but alsoregenerator-runtime/runtimeand all the nestedcore-jsentry points.For example, when targeting Chrome 72, it will apply this transformation:
Input
JavaScriptimport "core-js/es";
import "core-js/proposals/set-methods";
import "core-js/features/set/map";Output
JavaScriptimport "core-js/modules/es.array.unscopables.flat";
import "core-js/modules/es.array.unscopables.flat-map";
import "core-js/modules/es.object.from-entries";
import "core-js/modules/esnext.set.difference";
import "core-js/modules/esnext.set.intersection";
import "core-js/modules/esnext.set.is-disjoint-from";
import "core-js/modules/esnext.set.is-subset-of";
import "core-js/modules/esnext.set.is-superset-of";
import "core-js/modules/esnext.set.map";
import "core-js/modules/esnext.set.symmetric-difference";
import "core-js/modules/esnext.set.union";Unlike when using
core-js2, it doesn't transform@babel/polyfillimports because when used directly that package loads version 2 ofcore-js. -
Si usas
@babel/plugin-transform-runtime, necesitas usar la opcióncorejs: 3:JavaScriptplugins: [
["@babel/transform-runtime", {
corejs: 3,
}]
]Puedes eliminar
@babel/runtime-corejs2, pero debes instalar@babel/runtime-corejs3:npm remove @babel/runtime-corejs2
npm install --save @babel/runtime-corejs3 -
@babel/polyfillno es un plugin ni un preset, sino un paquete de runtime: si añadiéramos una opción para cambiar entrecore-js@2ycore-js@3, ambas versiones del paquete tendrían que incluirse en tu bundle. Por esta razón, decidimos marcarlo como obsoleto: ahora deberías cargarcore-jspara los polyfills, yregenerator-runtime/runtimesi estás transformando generadores:JavaScript// before
import "@babel/polyfill";
// after
import "core-js/stable";
import "regenerator-runtime/runtime";Esto te permite cargar cualquier versión que desees y actualizar ambos paquetes de forma independiente.
Si te interesa, puedes revisar el código fuente antiguo de
@babel/polyfillparacore-js@2: packages/babel-polyfill/src/index.js.
Aplicación Parcial (#9343 y #9474)
Esta versión incluye soporte tanto en @babel/parser como en la transformación para la propuesta de aplicación parcial, actualmente en Etapa 1 (última presentación en julio de 2018). Todo el trabajo de implementación fue realizado por Behrang Yarahmadi, patrocinado por Trivago.
Esta nueva característica permite vincular algunos argumentos y el receptor this de funciones, similar al método existente Function#bind pero con menos limitaciones.
const half = divide(?, 2); // half = num => divide(num, 3)
half(6); // 3
element.addEventListener(
"click",
// handleEvent will be called with the correct "this".
this.handleEvent("click", ?) // e => this.handleEvent("click", e)
);
También es muy útil junto con la propuesta del operador pipeline (especialmente al usar las variantes "minimal" o "F-sharp"), ya que evita el uso de muchas funciones flecha:
let newScore = player.score
|> add(?, 7)
|> clamp(0, 100, ?);
// Without this proposal:
let newScore = player.score
|> (_ => add(_, 7))
|> (_ => clamp(0, 100, _));
Puedes probarlo añadiendo @babel/plugin-proposal-partial-application a tu configuración, o activando el preset stage 1 en el REPL online!
Aunque la propuesta también describe aplicación parcial para literales de plantilla etiquetados, esto no se implementó porque probablemente se eliminará.
Métodos privados estáticos (#9446)
class Person {
static #is(obj) {
return obj instanceof Person;
}
constructor(name) {
if (Person.#is(name)) {
throw "It is already a person!";
}
}
}
¡Nuevamente gracias a Tim (Bloomberg) por implementar esta propuesta!
Si ya usas métodos privados de instancia, puedes usar esta nueva característica sin configuración adicional. De lo contrario, añade @babel/plugin-proposal-private-methods a tu lista de plugins. En el REPL online está activado con el preset stage-3.
¡El soporte para características privadas de clases está a solo un paso de completarse! 😄
| Class Private | Instance | Static |
|---|---|---|
Fields class A { #a = 1 } | 7.0.0 | 7.1.0 |
Methods class A { #a() {} } | 7.2.0 | 7.4.0 |
Accessors class A { get #a() {} } | 7.3.0 | ✖️ |
Soporte para TypeScript 3.4 RC (#9529 y #9534)
TypeScript 3.4 RC se lanzó hace unos días, ¡y gracias a Tan Li Hau ya es compatible con Babel!
Hay dos nuevas características para anotaciones de tipos: contextos const (que marcan un objeto como "inmutable profundo") y el modificador readonly para arreglos y tuplas.
const student = {
name: "Joe Blogs",
marks: [25, 23, 30]
} as const;
const vowels: readonly string[] = ["a", "e", "i", "o", "u"];
Ten en cuenta que TypeScript 3.4 RC no es una versión estable, por lo que deberías esperar hasta el lanzamiento oficial de TypeScript 3.4: puedes suscribirte al blog de TypeScript para recibir notificaciones cuando esté disponible. 🙂
Expresiones entre paréntesis (#8025)
Los paréntesis generalmente no son significativos para los compiladores de JavaScript o generadores de código: solo son "pistas" que indican al parser que ciertos nodos tienen diferente precedencia a la predeterminada:
| Code | 1 + 2 * 3 / 1 + (2 * 3) | (1 + 2) * 3 |
|---|---|---|
| AST structure | ![]() | ![]() |
Cuando se genera el AST, la precedencia de las operaciones se determina por la estructura del árbol y no por los paréntesis originales: por esta razón Babel no los rastreaba.
Al imprimir un AST, @babel/generator no tiene conocimiento sobre el formato original y solo genera paréntesis donde son necesarios.
Existen situaciones donde esto causa problemas a los usuarios. Por ejemplo, al usar Google Closure Compiler, los paréntesis marcan expresiones de conversión de tipo:
/** @type {!MyType} */ (valueExpression)
Ya teníamos un nodo ParenthesizedExpression para representar paréntesis, pero nunca lo generaba @babel/parser y solo podía inyectarse mediante plugins personalizados. Gracias al trabajo de Erik Arvidsson, ¡ahora puedes usar la opción createParenthesizedExpressions en el parser para rastrearlos automáticamente!
| Code | 1 + (2 * 3) | (1 + 2) * 3 |
|---|---|---|
| AST structure | ![]() | ![]() |
Cumplimiento de especificaciones en @babel/parser
Daniel está haciendo que @babel/parser cumpla cada vez más con la especificación ECMAScript: ahora pasa el 98.97% de las pruebas en la suite Test262. 😎
Esta versión hace que @babel/parser conozca las reglas de alcance de JavaScript: ahora sabe qué variables están declaradas, si hay conflictos, si están elevadas (hoisted) o no, y si una construcción sintáctica específica está permitida en su contexto.
Todos estos ejemplos inválidos ahora se reportan correctamente como errores, evitando la necesidad de invalidarlos manualmente en cada herramienta que usa @babel/parser:
let a, a; // Duplicate declaration 💥
if (foo) {
if (bar) { var b }
let b; // Duplicate declaration, again 💥
}
export { Foo }; // Error, Foo is not declared ❓
class C {
constructor() {
super(); // Super in a non-derived class 🤔
}
method(d, d) {} // Duplicate parameter 💥
}
Marcadores de posición en código (#9364)
El código no siempre está destinado a ser escrito directamente por humanos: ¿qué pasa si se necesita generar código usando una plantilla predefinida?
Las plantillas se usan frecuentemente para generar código HTML, ya sea con lenguajes como PHP o motores como Handlebars:
<!-- PHP -->
<section>
<h1><?= $title ?></h1>
<main><?= $body ?></main>
</section>
<!-- Handlebars -->
<section>
<h1>{{ title }}</h1>
<main>{{ body }}</main>
</section>
Si has desarrollado algún plugin de Babel, probablemente usaste @babel/template: una utilidad que permite hacer lo mismo pero generando código JavaScript:
const buildAssign = template`
var NAME = VALUE;
`;
const result = buildAssign({
NAME: varName,
VALUE: varValue,
});
Hasta ahora, @babel/template usaba identificadores en mayúsculas como "marcadores de posición" que luego debían reemplazarse. Aunque este enfoque funcionaba bien en muchos casos, tenía ciertas limitaciones:
-
Por defecto, todo identificador en mayúsculas se marcaba como placeholder y
@babel/templatearrojaba error si no se reemplazaba. -
No era posible colocar un marcador donde no se permite un identificador, como en el cuerpo de una función o declaraciones exportadas.
Para resolver estos problemas, introdujimos un nuevo elemento sintáctico que puede reemplazar cualquier nodo: %%placeholder_name%%.
const buildLazyFn = template`
function %%name%%(%%params%%) {
return function () %%body%%;
}
`;
const result = buildLazyFn({
name: functionName,
params: functionParams,
body: functionBody,
});
Esta funcionalidad fue patrocinada por Stripe (a través de Runkit). Estamos experimentando con nuevas formas de patrocinio para Babel, y por primera vez una empresa financió directamente la implementación de una característica pagando a un miembro del equipo. Si tu empresa quiere patrocinar la implementación de una propuesta de ECMAScript o mejoras generales en Babel, ¡contáctanos!



