Saltar al contenido principal

Babili (babel-minify)

· 9 min de lectura
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 →

¡Hemos lanzado Babili en versión beta (0.0.1) hace unos días bajo licencia MIT!

¡Pruébalo en el REPL de Babel y reporta cualquier error u optimización potencial que podamos implementar! También hay un canal de Slack #minify.

Existen muchas preguntas (válidas) sobre por qué un nuevo minificador es una buena idea, y este post busca responderlas.

TL;DR: Babili puede aceptar código ES2015+ como entrada, mientras que los minificadores actuales están mayormente limitados a ES5, lo que requiere transpilar el código antes de minificarlo. Esto se está volviendo innecesario a medida que se envía ES2015 directamente a los clientes. Babili también es modular/flexible (al ser un preset de Babel soporta plugins de usuario) y puede usarse como preset o herramienta CLI. Además, podrá realizar optimizaciones específicas para ES2015+.

Pronunciación

Shell
# sounds like "bah billy" or "Babadi" (from DBZ)
say Babili

Babili significa Babilonia en acadio.

Si no recuerdas el nombre, babel-minify también funciona (creamos un issue sobre el nombre).

¿Por qué minificar?

Básicamente, la minificación elimina caracteres innecesarios de un programa sin alterar su funcionalidad: comentarios, espacios en blanco, saltos de línea y paréntesis adicionales. La minificación avanzada puede transformar programas en equivalentes más pequeños y eliminar código redundante o inalcanzable.

La minificación es útil principalmente para reducir el tamaño de la carga JavaScript enviada del servidor al cliente: los usuarios descargarán menos código para usar tu sitio. La minificación avanzada también puede reducir el tiempo de análisis (menos código que analizar) y en algunos casos acelerar la ejecución (ej: optimizaciones como inlining de funciones).

Minificadores actuales

Herramientas como Uglify aún no soportan versiones recientes de ECMAScript (todavía no: rama harmony).

Actualmente usamos herramientas como Babel para compilar código ES2015 a ES5 y soportar navegadores antiguos. Luego aplicamos algo como Uglify para reducir el tamaño del bundle.

A medida que los navegadores implementan más características de ES2015 y dejamos de soportar versiones antiguas, existe una ventana móvil entre la versión de ECMAScript que escribes y la versión objetivo para minificar. Pero como Uglify no puede analizar ES2015+, aún necesitarías compilar primero a ES5.

Babili

Ahí es donde entra Babili.

Babili entiende ES2015+ porque está construido con la cadena de herramientas de Babel. Está implementado como un conjunto de plugins de Babel, consumible mediante el preset babili.

Ejemplo

Supongamos que apuntamos a las últimas versiones de Chrome, Firefox, Edge y Safari, todas compatibles con clases ES2015. Compilar clases ES2015 a funciones constructoras y métodos de prototipo (ES5) genera más código (y potencialmente pierde optimizaciones específicas que los navegadores tengan para clases).

JavaScript
class Mangler {
constructor(program) {
this.program = program;
}
}
// need this since otherwise Mangler isn't used
new Mangler();

Antes, podríamos ejecutar Babel para transpilar la clase en una función y luego aplicar Uglify al código transpilado antes de enviarlo al navegador.

JavaScript
// ES2015 code -> Babel -> Uglify/Babili -> Minified ES5 Code
var a=function a(b){_classCallCheck(this,a),this.program=b};a();

Con Babili, puedes simplemente ejecutar el minificador que opera directamente sobre código ES2015.

JavaScript
// ES2015 code -> Babili -> Minified ES2015 Code
class a{constructor(b){this.program=b}}new a;

También es importante señalar que esto no es exclusivo de ES2015. Dado que Babel se actualiza junto con ECMAScript (ES2015, ES2016 y ahora ES2017) y sigue el proceso de propuestas para características experimentales (con nuestros presets stage-x), el minificador podrá generar cualquier versión compatible de ECMAScript.

En el futuro, podríamos aprovechar la información sintáctica de ES2015+ disponible en tiempo de compilación (por ejemplo, saber que cierta función es una arrow function o que un binding tiene scope de bloque) para realizar optimizaciones avanzadas. Además, podremos utilizar creativamente el conocimiento de que estamos orientando a entornos ES2015+.

¡Estamos recién comenzando, así que avísanos si tienes alguna idea!

Algunos de los Plugins

Para ilustrar algunas transformaciones:

babel-plugin-minify-constant-folding:

Evalúa expresiones e inserta el resultado en línea. Actualmente solo maneja números y cadenas.

JavaScript
2 * 3;
"b" + a + "c" + "d" + g + z + "f" + "h" + "z"
JavaScript
6;
"b" + a + "cd" + g + z + "fhz";

babel-plugin-minify-mangle-names:

Renombrado de variables con conciencia de contexto y scope.

JavaScript
var globalVariableName = 42;
function foo() {
var longLocalVariableName = 1;
if (longLocalVariableName) {
console.log(longLocalVariableName);
}
}
JavaScript
var globalVariableName = 42;
function foo() {
var a = 1;
if (a) {
console.log(a);
}
}

Uso

Preset de Babel

Si ya usas Babel, basta con añadir el preset babili (babel-preset-babili) a tu configuración.

Conviene habilitarlo solo en producción usando la opción env, que utiliza process.env.BABEL_ENV o process.env.NODE_ENV.

Shell
$ npm install babel-preset-babili --save-dev
JavaScript
// previous .babelrc
{ "presets": ["es2015"] }
// .babelrc
{
"presets": ["es2015"],
"env": {
"production": {
"presets": ["babili"]
}
}
}

Un desafío al usar Babili como preset es que se ejecuta por archivo, no sobre el bundle completo. La minificación suele ocurrir después del bundling, como con "UglifyJsPlugin" en webpack. Sin embargo, esta separación podría eliminar beneficios de velocidad (por medir) al realizar transpilación/minificación en un solo paso. Debemos explorar cómo mejorar la integración o transferir información al bundler.

CLI de Babili

Si no usas Babel, emplea nuestra herramienta CLI independiente babili (actualmente un wrapper de babel-cli + el preset). Puedes ejecutarla después de transpilar (o no) como reemplazo de Uglify.

Shell
$ npm install babili --save-dev
Shell
$ babili src -d lib
# equivalent to
# babel src -d lib --presets=babili --no-babelrc

Webpack

Usa el preset directamente con babel-loader.

Shell
$ npm install babel-core babel-loader babel-preset-babili
JavaScript
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel',
query: {
presets: ['babili']
}
}
]
}

O utilízalo por separado con babili-webpack-plugin (creado por @boopathi, quien también contribuye a Babili).

Shell
$ npm install babili-webpack-plugin --save-dev
JavaScript
// webpack.config.js
const BabiliPlugin = require("babili-webpack-plugin");
module.exports = {
entry: //...,
output: //...,
plugins: [
new BabiliPlugin(options)
]
}

¡Buscamos mejorar la integración con Webpack/bundlers próximamente! Consulta también #100.

Pros y Contras

Ventajas de Uglify

  • No requiere cambios en tooling existente si ya minificas.

  • Probado en batalla/listo para producción (¡lleva años en uso y tiene amplia adopción (todos lo usamos)!

  • Es súper rápido y ya genera código compacto.

Contras de Uglify

  • Sistema propio de análisis/herramientas, lo que dificulta optimizar ES2015+ y realizar cambios.

  • No es modular, y actualmente no permite crear plugins propios o estrategias de minificación externas al núcleo.

Pros de Babili:

  • Conoce ES2015+ (no requiere configuraciones especiales gracias al parser Babylon) y se actualizará con los estándares/navegadores mediante Babel.

  • Utiliza la infraestructura existente de Babel, puede usarse como preset o herramienta independiente.

  • Potencial para transformaciones inteligentes personalizadas (React/Flow, etc.).

  • Podría usar anotaciones de Flow/TypeScript para habilitar minificaciones avanzadas.

  • Cada paso de minificación puede dividirse en su propio plugin, con amplias opciones de personalización. Esto facilita contribuciones y reporte de errores específicos. También permite crear plugins experimentales antes de integrarlos al núcleo.

    • Ejemplo: este plugin convierte true en !0 de forma sencilla.
  • Transición sencilla para quienes ya usan transpilación con Babel.

Contras de Babili:

  • Es una versión temprana, aún con pocos usuarios. Los primeros adoptantes enfrentarán una herramienta menos probada que Uglify inicialmente.

  • Actualmente tiene menor rendimiento/tamaño que Uglify en nuestras pruebas comparativas, pero mejoraremos esto.

TL;DR: Babili podrá mantenerse al día con el estándar ECMAScript y adaptarse a los entornos objetivo. Tiene gran potencial: aunque hoy es menos maduro que Uglify al ser nuevo, las optimizaciones continuas y adopción creciente lo harán competitivo.

Cómo ayudar

Amjad llevaba tiempo trabajando en el proyecto, pero decidimos lanzarlo antes como beta para que la comunidad pruebe y contribuya reportando errores o enviando parches.

¡El proyecto es joven y hay mucho por hacer! Nuestra prioridad es estabilizar Babili para el lanzamiento 1.0.0.

Trabajaremos para igualar la velocidad y compacidad de Uglify/Closure Compiler en modo simple.

  • Pruebas en más bases de código: Ayudarán enormemente. Un minificador procesa todo el código, exponiendo casos límite/errores no cubiertos en pruebas unitarias básicas. Queremos facilitar el reporte de errores; el REPL ya soporta el minificador, facilitando reproducción. Futuramente añadiremos opciones para activar plugins específicos y aislar pasos.

  • Infraestructura/mantenimiento: Crearemos benchmarks más robustos y tests de integración en proyectos open-source populares (ejecutar minificador y luego tests unitarios del proyecto).

  • Verificar salidas: Si algo puede simplificarse más, será fácil reportarlo y sugerir nuevas transformaciones o plugins. La modularidad permite crear plugins propios que luego podrían integrarse al preset principal.

Un enorme agradecimiento a Amjad (@amasad) por iniciar este proyecto y a Facebook por permitirnos publicarlo bajo la organización Babel como proyecto con licencia MIT. Sebastian (@kittens) fue obviamente una pieza fundamental ya que esto no habría sido posible sin Babel. ¡También gracias a James (@thejameskyle) y Juriy (@kangax) por ayudar a concretar este lanzamiento! Queremos reconocer especialmente a Boopathi (@boopathi), a quien invitamos a colaborar tras ver su trabajo en su propio proyecto babel-minify.