Saltar al contenido principal

Actualización a Babel 7 (API)

Traducción Beta No Oficial

Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →

Dirige a los usuarios a este documento cuando actualicen a Babel 7.

También consulta la guía de migración a v7 para otros cambios a nivel de usuario.

Todos los paquetes de Babel

Soporte para NodeJS

high

Se ha eliminado el soporte para Node.js 0.10 y 0.12 ya que ambas versiones están fuera de mantenimiento.

Cambios en las exportaciones

medium

Se eliminó el uso del plugin add-module-exports en los paquetes de Babel. Este se utilizaba anteriormente para evitar un cambio incompatible en nuestras exportaciones. Si importas un paquete de Babel en una biblioteca, es posible que necesites usar .default cuando utilices require en lugar de import.

@babel/core

Se cambió ast a false por defecto por rendimiento (la mayoría de herramientas no lo usan) babel/babel#7436.

Se eliminó la clase Pipeline (expuesta públicamente pero no documentada). Es mejor usar los métodos de transformación expuestos directamente por @babel/core babel/babel#5376.

Se eliminaron los métodos auxiliares babel.util.*, y util.EXTENSIONS se movió a babel.DEFAULT_EXTENSIONS babel/babel#5487.

Las llamadas a babel.transform o cualquier otra función de transformación pueden devolver null si el archivo coincide con un patrón ignore o no coincide con un patrón only babel/babel#5487.

Se eliminó la opción opts.basename expuesta en state.file.opts. Si la necesitas, es mejor que la construyas tú mismo a partir de opts.filename babel/babel#5467.

Se eliminó resolveModuleSource. Recomendamos usar la opción 'resolvePath' de babel-plugin-module-resolver@3 babel/babel#6343

Se eliminó babel.analyse porque solo era un alias de babel.transform

Se eliminó path.mark() ya que no lo usábamos y se puede implementar en tu propio plugin.

Se eliminó babel.metadata ya que los metadatos del plugin generado siempre se incluyen en el resultado de salida.

Se eliminó path.hub.file.addImport. Puedes usar el módulo @babel/helper-module-imports en su lugar.

+  import { addDefault } from "@babel/helper-module-imports";
function importModule(pkgStore, name, path) {
- return path.hub.file.addImport(resolvePath(pkgStore, name, path), 'default', name);
+ return addDefault(path, resolvePath(pkgStore, name, path), { nameHint: name });
}

Cambios en la configuración

Hemos realizado cambios importantes en cómo funciona la búsqueda de configuración:

Por defecto, al buscar archivos .babelrc para un archivo dado, se detiene en package.json.

Para cualquier archivo específico, Babel v6 sigue buscando en la jerarquía de directorios hasta encontrar un archivo de configuración. Esto significa que tu proyecto podría romperse si utiliza un archivo de configuración encontrado fuera de la raíz del paquete, como en el directorio home.

Se añade soporte para un archivo babel.config.js similar a lo que hace Webpack

Dado que esto rompería el funcionamiento de un monorepo (incluido el propio Babel), estamos introduciendo un nuevo archivo de configuración que básicamente elimina la naturaleza jerárquica de las configuraciones.

Se incluye una opción root que por defecto es el directorio de trabajo actual para localizar el archivo. Además, no se carga relativamente, por lo que manejará correctamente los symlinks, mientras que antes podrías haber tenido que codificar rígidamente las rutas en webpack.

Consulta la documentación de babel.config.js para más información: configuración para todo el proyecto

Este archivo combinado con la nueva propiedad overrides y env te permite tener un único archivo de configuración que funcione para todos los archivos de un proyecto, a diferencia de múltiples archivos de configuración por carpeta.

También excluimos node_modules por defecto y solo buscamos en la raíz, a menos que optes por configurar un array de la opción .babelrcRoots como "babelrcRoots": [".", "node_modules/pkgA"]

Verificación de la versión de Babel #7450

Los plugins pueden verificar que se carguen con cierta versión de Babel. La API expondrá un método assertVersion, donde puedes pasar una versión semver.

El helper declare se utiliza para mantener compatibilidad con versiones anteriores (v6).

JavaScript
import { declare } from "@babel/helper-plugin-utils";

export default declare(api => {
api.assertVersion(7);
// ...
});

Plugins y presets de Babel

Actualmente toma como primer parámetro el objeto babel, las opciones del plugin/preset y el dirname

JavaScript
module.exports = function(api, options, dirname) {};

babel-parser (conocido como Babylon)

Se eliminó la opción de plugin * #301 low

Esta opción se agregó inicialmente en v6.14.1 (17 nov 2016), por lo que es poco probable que alguien la estuviera usando.

Esta opción general fue eliminada; en su lugar debes especificar qué plugins quieres activar.

Pensamos que sería útil para herramientas que no tendrían que actualizar constantemente su configuración, pero también significa que no podemos hacer fácilmente cambios con ruptura de compatibilidad.

Antes:

JavaScript
babelParser.parse(code, {
plugins: ["*"],
});

Puedes obtener el comportamiento antiguo usando:

JavaScript
babelParser.parse(code, {
plugins: [
"asyncGenerators",
"classProperties",
"decorators",
"doExpressions",
"dynamicImport",
"exportExtensions",
"flow",
"functionBind",
"functionSent",
"jsx",
"objectRestSpread",
],
});

Consulta las opciones de plugins de Babylon.

Se renombró el plugin decorators a decorators-legacy medium

Se renombró para alinearse con la opción legacy de @babel/plugin-proposal-decorators. Se implementó un nuevo plugin decorators que sigue la nueva propuesta de decoradores.

Las dos versiones de las propuestas tienen sintaxis diferentes, por lo que se recomienda encarecidamente usar decorators-legacy hasta que Babel implemente las nuevas semánticas.

Se eliminó el plugin classConstructorCall #291 low

@babel/traverse

Se eliminó el soporte para bindings de flow babel/babel#6528

Este cambio se debe a que declare var foo no introduce un binding local, sino que representa uno global.

getFunctionParent ya no devolverá Program, usa getProgramParent en su lugar #5923. low

No tiene sentido que una función llamada getFunctionParent también devuelva Program, por lo que se eliminó ese comportamiento.

Para obtener el comportamiento equivalente, deberás realizar un cambio como:

- path.scope.getFunctionParent()
+ path.scope.getFunctionParent() || path.scope.getProgramParent()

Las APIs de reemplazo/eliminación de rutas ahora devuelven un array de nuevas rutas low

Por ejemplo, usar Path#insertBefore o Path#replaceWith ahora siempre devolverá un array de las rutas recién insertadas/reemplazadas.

JavaScript
const node = t.nullLiteral();
const [replaced] = path.replaceWith(node);
replace.node === node; // => true

Esto es especialmente útil al insertar varios nodos en un ámbito superior, ya que puedes llamar inmediatamente a las APIs Path en la nueva Path del nodo.

JavaScript
const parent = path.findParent(() => /* some selection criteria */);
const helperPaths = path.unshiftContainer("body", helpers);
// helperPaths can now be referenced, manipulated, etc.

Cambios en el AST

Se añade el nodo InterpreterDirective #7928

Babylon ya analizaba "shebangs" (#!env node) pero los colocaba como comentario en el nodo Program. Ahora creamos un nodo específico para ello.

Se añade un nuevo campo interpreter al nodo Program.

JavaScript
extend interface Program {
interpreter: InterpreterDirective;
}

Se añade el nodo InterpreterDirective

JavaScript
interface InterpreterDirective <: Node {
type: "InterpreterDirective";
value: string;
}

Constructores de nodos JSX* y TS* (del paquete @babel/types) renombrados

Se cambió el caso: jsx y ts ahora están en minúsculas.

- t.jSXIdentifier()
+ t.jsxIdentifier()

En general, hemos diferenciado los tipos de nodos con TypeAnnotation para Flow y TSTypeAnnotation para TypeScript, por lo que para los nodos de tipo compartidos, TypeScript tiene prefijo TS.

Campo .expression eliminado de ArrowFunctionExpression

Se eliminó el campo expression para eliminar dos fuentes de verdad distintas y evitar que los plugins tuvieran que sincronizarlas manualmente. Ahora simplemente puedes verificar si el cuerpo de la función es un BlockStatement o no:

  return {
visitor: {
ArrowFunctionExpression({ node }) {
- if (node.expression) {
+ if (node.body.type !== "BlockStatement") {
// () => foo;
}
}
}
};

Tokens eliminados

En versiones anteriores, los tokens siempre se adjuntaban al AST en el nivel superior. En la última versión de @babel/parser eliminamos este comportamiento y lo desactivamos por defecto para mejorar el rendimiento. Todos los usos en Babel mismo se han eliminado y @babel/generator ya no usa tokens para el formateo.

Si tu plugin de Babel usa tokens actualmente, evalúa si sigue siendo necesario e intenta eliminar su uso si es posible. Si tu plugin realmente depende de obtener tokens, puedes reactivarlo, pero considera esto solo si no hay otra alternativa, ya que afectará el rendimiento.

Para activarlo, debes establecer la opción tokens de babylon en true. Puedes hacerlo directamente desde tu plugin.

JavaScript
export default function() {
return {
manipulateOptions(opts, parserOpts) {
parserOpts.tokens = true;
},
...
};
}

Renombrados

Los siguientes nodos han sido renombrados:

Name 6.xName 7.xExamplePR
ExistentialTypeParamExistsTypeAnnotationtype A = B<*>;#322
NumericLiteralTypeAnnotationNumberLiteralTypeAnnotationtype T = 0;#332

Además de los nodos AST, todas las funciones correspondientes en @babel/types también han sido renombradas.

 import * as t from "@babel/types";

return {
- ExistentialTypeParam(path) {
- const parent = path.findParent((path) => path.isExistentialTypeParam());
- t.isExistentialTypeParam(parent);
+ ExistsTypeAnnotation(path) {
+ const parent = path.findParent((path) => path.isExistsTypeAnnotation());
+ t.isExistsTypeAnnotation(parent);

- return t.existentialTypeParam();
+ return t.existsTypeAnnotation();
},
- NumericLiteralTypeAnnotation(path) {
- const parent = path.findParent((path) => path.isNumericLiteralTypeAnnotation());
- t.isNumericLiteralTypeAnnotation(parent);
+ NumberLiteralTypeAnnotation(path) {
+ const parent = path.findParent((path) => path.isNumberLiteralTypeAnnotation());
+ t.isNumberLiteralTypeAnnotation(parent);

- return t.numericLiteralTypeAnnotation();
+ return t.numberLiteralTypeAnnotation();
}
};

Reemplazados

En los siguientes nodos AST, el valor del campo variance ha cambiado de ser un string simple a ser su propio nodo AST llamado Variance. #333

Este campo solo está disponible al activar el plugin flow en babylon.

  • ObjectProperty

  • ObjectMethod

  • AssignmentProperty

  • ClassMethod

  • ClassProperty

  • Property

El tipo del nuevo nodo Variance se ve así:

JavaScript
type VarianceNode = {
type: "Variance",
kind: "plus" | "minus",
};
 return {
Property({ node }) {
- if (node.variance === "plus") {
+ if (node.variance.kind === "plus") {
...
- } else if (node.variance === "minus") {
+ } else if (node.variance.kind === "minus") {
...
}
}
};

Cambios de ubicación

La información de ubicación de ObjectTypeIndexer ha cambiado para no incluir punto y coma. Esto se hizo para alinearse con el flow-parser y tener la misma información de ubicación. #228

Ejemplo:

JavaScript
var a: { [a: number]: string };
 {
"type": "ObjectTypeIndexer",
"start": 9,
- "end": 29,
+ "end": 28,
"loc": {
"start": {
"line": 1,
"column": 9,
},
"end": {
"line": 1,
- "column": 29
+ "column": 28
}
}
}

Eliminación

ForAwaitStatement

El nodo AST ForAwaitStatement ha sido eliminado y se reemplaza por el campo await en el nodo ForOfStatement #349

 interface ForOfStatement <: ForInStatement {
type: "ForOfStatement";
+ await: boolean;
}
 return {
- ForAwaitStatement(path) {
- ...
+ ForOfStatement(path) {
+ if (path.node.await) {
+ ...
+ }
}
};

RestProperty y SpreadProperty

Los dos nodos AST RestProperty y SpreadProperty han sido eliminados en favor de reutilizar RestElement y SpreadElement #384

 return {
SpreadElement(path) {
- ...
- },
- SpreadProperty(path) {
- ...
+ if (path.parentPath.isObjectExpression()) {
+ ...
+ } else if (path.parentPath.isArrayExpression()) {
+ ...
+ }
},
RestElement(path) {
- ...
- },
- RestProperty(path) {
- ...
+ if (path.parentPath.isObjectPattern()) {
+ ...
+ } else if (path.parentPath.isArrayPattern()) {
+ ...
+ }
}
};

Consulta nuestro PR de actualización para Babel y la especificación AST de Babylon para más información.