Reduce y comprime las cargas útiles de red con brotli

Michael DiBlasio
Michael DiBlasio

Este codelab es una extensión del codelab para reducir y comprimir cargas útiles de red, y se da por sentado que 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 las proporciones de compresión y el tamaño general de tu app.

Captura de pantalla de la app

Medir

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

  1. Haz clic en Remix para editar para que el proyecto se pueda editar.
  2. Para obtener una vista previa del sitio, presiona Ver app. Luego, presiona Pantalla completa pantalla completa.

En el codelab para reducir y comprimir 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 Brotli puede reducir aún más el tamaño de este paquete.

Compresión de Brotli

Brotli es un algoritmo de compresión más reciente que puede proporcionar resultados de compresión de texto aún mejores que gzip. Según CertSimple, el rendimiento de Brotli es el siguiente:

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

Para usar Brotli, tu 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 a través del campo Content-Encoding de la pestaña Red de las 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 los recursos sobre la marcha a medida que el navegador los solicita.

Ventajas

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

Desventajas

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

Compresión dinámica con Node/Express

El archivo server.js se encarga de configurar el servidor de nodo 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);
});

En la actualidad, todo lo que hace es importar express y usar el middleware express.static para cargar todos los archivos HTML, JS y CSS estáticos en public/directory (y esos archivos se crean por webpack con cada compilación).

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

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

Luego, impórtalo al archivo del servidor, server.js:

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

Agrégalo como middleware antes de que se active 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 dinámica Brotli

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

Compresión estática

La idea detrás de la compresión estática es comprimir y guardar los recursos con anticipación.

Ventajas

  • La latencia debido a los altos niveles de compresión ya no es un problema. No es necesario que suceda nada sobre la marcha para comprimir los archivos, ya que ahora se pueden recuperar directamente.

Desventajas

  • Los recursos deben comprimirse con cada compilación. Los tiempos de compilación pueden aumentar de manera significativa 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, la configuración del paquete web se puede modificar para comprimir los elementos como parte del paso de compilación. Para ello, se puede usar brotli-webpack-plugin.

Primero, 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');

Inclúyelo en el array de complementos:

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

El array del complemento usa los siguientes argumentos:

  • asset: Es el nombre del recurso de destino.
  • [file] se reemplaza por el nombre del archivo del activo original.
  • test: Se procesan todos los elementos que coinciden con esta regex (es decir, los elementos de JavaScript que terminan en .js).

Por ejemplo, se cambiará 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 consultar el contenido del directorio final public/ que entrega el servidor de nodos.

  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 estática Brotli

La versión comprimida con Brotli del paquete, main.bundle.js.br, ahora también se guarda aquí y es ~76% más pequeña en tamaño (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 originales de JS. 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 usa 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 todos los extremos que se activan con el 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 con cualquier devolución de llamada que pueda ocurrir a continuación.

Debido a que es posible que algunos navegadores no admitan la compresión brotli, confirma que brotli sea compatible antes de mostrar el archivo comprimido. 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 observar el panel Network.

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

¡Listo! ¡Has utilizado 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. Si es compatible, brotli es un algoritmo de compresión más potente que gzip.