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 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 app

Medir

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

  1. Haz clic en Remix para editar 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 anterior para reducir y comprimir las cargas útiles de red, se redujo 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 para HTML
  • Un 17% más pequeño que gzip para CSS

Para usar Brotli, tu servidor debe ser compatible con 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 Network de las Herramientas para desarrolladores de Chrome (Command+Option+I o Ctrl+Alt+I):

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

Cómo habilitar Brotli

La forma en que configures 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ático).

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 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 tarda más. Esto puede provocar un impacto en el rendimiento, ya que el usuario espera a 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 se encarga de configurar el servidor de nodo 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 esto solo importa express y usa 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 activos 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"
},

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

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

Y agrégalo como un middleware antes de que se monte 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 red:

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 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 activos comprimidos y guardados con anticipación.

Ventajas

  • La latencia debido a los altos niveles de compresión ya no es un problema. No se necesita hacer 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 de compresión altos.

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

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

Comienza por agregarlo como 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, además, 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 activo de destino.
  • [file] se reemplaza por el nombre de 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, el nombre de main.js se cambiaría a main.js.br.

Cuando la app se vuelve a cargar y compilar, se crea una versión comprimida del paquete principal. Abre Glitch Console para ver el contenido 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 de Brotli del paquete, main.bundle.js.br, ahora también se guarda aquí y es alrededor de un 76% más pequeña (225 KB en comparación con 53 KB) que main.bundle.js.

A continuación, dile 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 primer argumento significa que esto funciona para cada extremo que se activa para recuperar un archivo JS.
  • Dentro de la devolución de llamada, .br se adjunta 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() se asegura de que la secuencia continúe con cualquier devolución de llamada que pueda ser la siguiente.

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

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 revisar el panel de red.

Tamaño del paquete de 53.1 KB (de 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.