Reduce y comprime las cargas útiles de red con brotli

Michael DiBlasio
Michael DiBlasio

Este codelab es una extensión del codelab de reducción y compresión de cargas útiles de red, y se da por sentado que ya conoces los conceptos básicos de la compresión. En comparación con otros algoritmos de compresión como gzip, en este codelab se explora cómo la compresión Brotli puede reducir aún más los índices de compresión y el tamaño general de tu app.

Captura de pantalla de la aplicación

Medir

Antes de comenzar a agregar optimizaciones, siempre es una buena idea analizar primero el estado actual de la aplicación.

  1. Haz clic en Remix to Edit para que el proyecto sea editable.
  2. Para obtener una vista previa del sitio, presiona Ver app. Luego, presiona Pantalla completa pantalla completa.

En el codelab de reducción y compresión de cargas útiles de red anterior, redujimos el tamaño de main.js de 225 KB a 61.6 KB. En este codelab, explorarás cómo la compresión de Brotli puede reducir aún más el tamaño de este paquete.

Compresión Brotli

Brotli es un algoritmo de compresión más nuevo que puede proporcionar resultados de compresión de texto aún mejores que gzip. Según CertSimple, el rendimiento de Brotli tiene las siguientes características:

  • Un 14% más pequeño que gzip para JavaScript
  • un 21% más pequeño que gzip para HTML
  • Un 17% más pequeño que gzip para CSS

Para usar Brotli, el servidor debe admitir HTTPS. Brotli es compatible con las versiones más recientes de la mayoría de los navegadores. Los navegadores compatibles con Brotli incluirán br en los encabezados Accept-Encoding:

Accept-Encoding: gzip, deflate, br

Puedes determinar qué algoritmo de compresión se usa en el campo Content-Encoding de la pestaña Red de Herramientas para desarrolladores de Chrome (Command+Option+I o Ctrl+Alt+I):

Panel de red

Habilitando Brotli

Compresión dinámica

La compresión dinámica implica comprimir elementos sobre la marcha a medida que el navegador los solicita.

Ventajas

  • No es necesario crear y actualizar las versiones comprimidas guardadas de los elementos.
  • La compresión sobre la marcha funciona especialmente bien para las páginas web que se generan de forma dinámica.

Desventajas

  • La compresión de archivos en niveles más altos para lograr mejores índices de compresión lleva más tiempo. Esto puede provocar un problema de rendimiento, ya que el usuario espera a que se compriman los elementos antes de que el servidor los envíe.

Compresión dinámica con Node y Express

El archivo server.js se encarga de configurar el servidor de Node que aloja la aplicación.

var express = require('express');

var app = express();

app.use(express.static('public'));

var listener = app.listen(process.env.PORT, function() {
  console.log('Your app is listening on port ' + listener.address().port);
});

Por el momento, lo único que hace es importar express y usar el middleware express.static para cargar todos los archivos HTML, JS y CSS estáticos en el public/directory (y esos archivos se crean mediante webpack con cada compilación).

Para garantizar que todos los recursos se compriman con brotli cada vez que se soliciten, se puede usar el módulo shrink-ray. Para comenzar, agrégalo como devDependency en package.json:

"devDependencies": {
  //...
  "shrink-ray": "^0.1.3"
},

Y, luego, impórtala en el archivo de servidor, server.js:

var express = require('express');
var shrinkRay = require('shrink-ray');

Además, agrégalo como middleware antes de activar express.static:

//...
var app = express();

// compress all requests
app.use(shrinkRay());

app.use(express.static('public'));

Ahora, vuelve a cargar la app y observa el tamaño del paquete en el panel Network:

Tamaño del paquete con compresión Brotli dinámica

Ahora puedes ver que brotli se aplica desde bz en el encabezado Content-Encoding. main.bundle.js se redujo de 225 KB a 53.1 KB. Esto es aproximadamente un 14% menor en comparación con gzip (61.6 KB).

Compresión estática

La idea detrás de la compresión estática es comprimir los recursos y guardarlos de antemano.

Ventajas

  • La latencia debida a altos niveles de compresión ya no es una preocupación. No es necesario que ocurra nada sobre la marcha para comprimir archivos, ya que ahora se pueden recuperar directamente.

Desventajas

  • Los recursos se deben comprimir con cada compilación. Los tiempos de compilación pueden aumentar significativamente si se usan niveles altos de compresión.

Compresión estática con Node/Express y webpack

Dado que la compresión estática implica comprimir archivos con anticipación, se puede modificar la configuración del paquete web para comprimir elementos como parte del paso de compilación. Se puede usar brotli-webpack-plugin para esto.

Para comenzar, agrégalo como devDependency en package.json:

"devDependencies": {
  //...
 "brotli-webpack-plugin": "^1.1.0"
},

Como cualquier otro complemento de webpack, impórtalo en el archivo de configuración, webpack.config.js:

var path = require("path");

//...
var BrotliPlugin = require('brotli-webpack-plugin');

Además, inclúyelo dentro del array de complementos:

module.exports = {
  // ...
  plugins: [
    // ...
    new BrotliPlugin({
      asset: '[file].br',
      test: /\.(js)$/
    })
  ]
},

El array de complementos usa los siguientes argumentos:

  • asset: Es el nombre del recurso de destino.
  • Se reemplazará [file] por el nombre de archivo del recurso original.
  • test: Se procesan todos los elementos que coinciden con esta expresión regular (es decir, los recursos de JavaScript que terminan en .js).

Por ejemplo, se cambiaría el nombre de main.js a main.js.br.

Cuando la app se vuelva a cargar y compilar, se creará una versión comprimida del paquete principal. Abre la consola de Glitch para ver el contenido del directorio final public/ que entrega el servidor de Node.

  1. Haz clic en el botón Herramientas.
  2. Haz clic en el botón Consola.
  3. En la consola, ejecuta los siguientes comandos para cambiar al directorio public y ver todos sus archivos:
cd public
ls -lh
Tamaño del paquete con compresión Brotli estática

La versión comprimida de brotli del paquete, main.bundle.js.br, ahora también se guarda aquí y es ~76% más pequeña (225 KB frente a 53 KB) que main.bundle.js.

A continuación, indícale al servidor que envíe estos archivos comprimidos con brotli cada vez que se soliciten sus versiones de JS originales. Para ello, define una ruta nueva en server.js antes de que los archivos se entreguen con express.static.

var express = require('express');

var app = express();

app.get('*.js', (req, res, next) => {
  req.url = req.url + '.br';
  res.set('Content-Encoding', 'br');
  res.set('Content-Type', 'application/javascript; charset=UTF-8');
  next();
});

app.use(express.static('public'));

app.get se usa para indicarle al servidor cómo responder a una solicitud GET para un extremo específico. Luego, se utiliza una función de devolución de llamada para definir cómo manejar esta solicitud. La ruta funciona de la siguiente manera:

  • Especificar '*.js' como primer argumento significa que esto funciona para cada extremo que se activa a fin de recuperar un archivo JS.
  • Dentro de la devolución de llamada, se adjunta .br a la URL de la solicitud y el encabezado de respuesta Content-Encoding se establece en br.
  • El encabezado Content-Type se establece en application/javascript; charset=UTF-8 para especificar el tipo de MIME.
  • Por último, next() garantiza que la secuencia continúe hasta cualquier devolución de llamada que pueda ser la siguiente.

Debido a que es posible que algunos navegadores no admitan la compresión de brotli, confirma que brotli sea compatible antes de mostrar el archivo comprimido brotli. Para ello, verifica que el encabezado de la solicitud Accept-Encoding incluya br:

var express = require('express');

var app = express();

app.get('*.js', (req, res, next) => {
  if (req.header('Accept-Encoding').includes('br')) {
    req.url = req.url + '.br';
    console.log(req.header('Accept-Encoding'));
    res.set('Content-Encoding', 'br');
    res.set('Content-Type', 'application/javascript; charset=UTF-8');
  }
  next();
});

app.use(express.static('public'));

Una vez que se vuelva a cargar la app, vuelve a ver el panel Network.

Tamaño del paquete de 53.1 KB (desde 225 KB)

¡Listo! Usaste la compresión Brotli para comprimir aún más tus recursos.

Conclusión

En este codelab, se ilustró cómo brotli puede reducir aún más el tamaño general de tu app. Cuando es compatible, brotli es un algoritmo de compresión más potente que gzip.