Reduce y comprime las cargas útiles de red con brotli

Michael DiBlasio
Michael DiBlasio

Este codelab es una extensión del codelab Reduce y comprime cargas útiles de red y supone 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 (br) puede reducir aún más las relaciones de compresión y el tamaño general de tu app.

Captura de pantalla de la aplicación

Medir

Antes de 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 se pueda editar.
  2. Para obtener una vista previa del sitio, presiona View App y, luego, Fullscreen pantalla completa.

En el codelab anterior sobre cómo reducir y comprimir cargas útiles de red, disminuimos 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 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 para HTML
  • Un 17% más pequeño que gzip para CSS

Para usar Brotli, tu servidor debe admitir HTTPS. Brotli es compatible con todos los navegadores modernos. Los navegadores que admiten Brotli incluirán br en los encabezados Accept-Encoding:

Accept-Encoding: gzip, deflate, br

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

Panel de red. En la columna Content-encoding, se muestran las codificaciones que se usan para varios recursos, incluidos gzip y brotli (br).

Cómo habilitar Brotli

La forma en que configuras un servidor web para enviar recursos codificados con Brotli depende de cómo planeas codificarlos. Tus opciones son comprimir los recursos de forma dinámica con Brotli en el momento de la solicitud (dinámica) o codificarlos con anticipación para que ya estén comprimidos cuando el usuario los solicite (estática).

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 ni actualizar versiones comprimidas guardadas de los recursos.
  • La compresión sobre la marcha funciona especialmente bien para las páginas web que se generan de forma dinámica.

Desventajas

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

Compresión dinámica con Node y Express

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

const express = require('express');
const app = express();
app.use(express.static('public'));

const listener = app.listen(process.env.PORT, function() {
  console.log(`Your app is listening on port ${listener.address().port}`);
});

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 webpack crea esos archivos 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. Para comenzar, agrégalo como un devDependency en package.json:

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

Y, luego, impórtalo en el archivo del servidor, server.js:

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

Y agrégalo como middleware antes de que se active express.static:

// ...
const 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 de redes:

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

Ahora puedes ver que brotli se aplica desde bz en el encabezado Content-Encoding. main.bundle.js se reduce de 225 KB a 53.1 KB. Esto es 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 tener recursos comprimidos y guardados con anticipación.

Ventajas

  • La latencia debido a los altos niveles de compresión ya no es un problema. No es necesario que ocurra 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 significativamente si se usan niveles de compresión altos.

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

Dado que la compresión estática implica comprimir archivos con anticipación, la configuración de webpack se puede modificar para comprimir los recursos como parte del paso de compilación. Para ello, se puede usar brotli-webpack-plugin.

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

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

Al igual que 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');

Y, luego, inclúyelo en el 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.
  • [file] se reemplaza por el nombre del archivo del recurso original.
  • test: Se procesan todos los recursos que coinciden con esta RegExp (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 vuelve a cargar y compilar, se crea una versión comprimida del paquete principal. Abre la consola de Glitch para ver qué hay dentro del directorio public/ final 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 con brotli del paquete, main.bundle.js.br, ahora también se guarda aquí y es aproximadamente un 76% más pequeña (225 KB en comparación con 53 KB) que main.bundle.js.

Luego, 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 se entreguen los archivos con express.static.

const express = require('express');
const 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 controlar esta solicitud. La ruta funciona de la siguiente manera:

  • Especificar '*.js' como el primer argumento significa que esto funciona para cada extremo que se activa para 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 ser la siguiente.

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

const express = require('express');
const 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 mirar el panel de redes.

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 se admite, brotli es un algoritmo de compresión más potente que gzip.