Réduire et compresser les charges utiles du réseau avec des brotli

Michael DiBlasio
Michael DiBlasio

Cet atelier de programmation est une extension de l'atelier de programmation sur la minification et la compression des charges utiles réseau. Il part du principe que vous maîtrisez les concepts de base de la compression. Par rapport à d'autres algorithmes de compression comme gzip, cet atelier de programmation explique comment la compression Brotli (br) peut réduire davantage les taux de compression et la taille globale de votre application.

Capture d'écran de l'application

Mesurer

Avant d'ajouter des optimisations, il est toujours judicieux d'analyser l'état actuel de l'application.

  1. Cliquez sur Remix to Edit (Remixer pour modifier) pour rendre le projet modifiable.
  2. Pour prévisualiser le site, appuyez sur Afficher l'application, puis sur Plein écran plein écran.

Dans l'atelier de programmation précédent sur la réduction et la compression des charges utiles réseau, nous avons réduit la taille de main.js de 225 Ko à 61,6 Ko. Dans cet atelier de programmation, vous allez découvrir comment la compression Brotli peut réduire encore davantage la taille de ce bundle.

Compression Brotli

Brotli est un algorithme de compression plus récent qui peut fournir des résultats de compression de texte encore meilleurs que gzip. Selon CertSimple, les performances de Brotli sont les suivantes :

  • 14 % plus petit que gzip pour JavaScript
  • 21 % plus petit que gzip pour HTML
  • 17 % plus petit que gzip pour les CSS

Pour utiliser Brotli, votre serveur doit être compatible avec HTTPS. Brotli est compatible avec tous les navigateurs modernes. Les navigateurs compatibles avec Brotli incluront br dans les en-têtes Accept-Encoding :

Accept-Encoding: gzip, deflate, br

Vous pouvez déterminer l'algorithme de compression utilisé à l'aide du champ Content-Encoding dans l'onglet "Réseau" des outils pour les développeurs Chrome (Command+Option+I ou Ctrl+Alt+I) :

Panneau "Réseau". La colonne "Encodage du contenu" affiche les encodages utilisés pour différents composants, y compris gzip et brotli (br).

Activer Brotli

La façon dont vous configurez un serveur Web pour envoyer des ressources encodées avec Brotli dépend de la manière dont vous prévoyez de les encoder. Vous pouvez compresser les ressources de manière dynamique avec Brotli au moment de la requête (compression dynamique) ou les encoder à l'avance afin qu'elles soient déjà compressées lorsque l'utilisateur les demande (compression statique).

Compression dynamique

La compression dynamique consiste à compresser les éléments à la volée lorsqu'ils sont demandés par le navigateur.

Avantages

  • Il n'est pas nécessaire de créer ni de mettre à jour les versions compressées enregistrées des composants.
  • La compression à la volée est particulièrement efficace pour les pages Web générées de manière dynamique.

Inconvénients

  • La compression des fichiers à des niveaux plus élevés pour obtenir de meilleurs taux de compression prend plus de temps. Cela peut entraîner une baisse des performances, car l'utilisateur doit attendre que les éléments soient compressés avant d'être envoyés par le serveur.

Compression dynamique avec Node et Express

Le fichier server.js est chargé de configurer le serveur Node qui héberge l'application.

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}`);
});

Tout ce que cela fait, c'est importer express et utiliser le middleware express.static pour charger tous les fichiers HTML, JS et CSS statiques dans public/directory (et ces fichiers sont créés par webpack à chaque compilation).

Pour vous assurer que tous les composants sont compressés à l'aide de Brotli chaque fois qu'ils sont demandés, vous pouvez utiliser le module shrink-ray. Commencez par l'ajouter en tant que devDependency dans package.json :

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

Importez-le dans le fichier du serveur, server.js :

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

Ajoutez-le en tant qu'intergiciel avant le montage de express.static :

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

// Compress all requests
app.use(shrinkRay());
app.use(express.static('public'));

Actualisez maintenant l'application et examinez la taille du bundle dans le panneau "Réseau" :

Taille du bundle avec compression Brotli dynamique.

Vous pouvez désormais voir que brotli est appliqué à partir de bz dans l'en-tête Content-Encoding. main.bundle.js est passé de 225 Ko à 53,1 Ko ! Cela représente environ 14 % de moins que gzip (61,6 Ko).

Compression statique

L'idée derrière la compression statique est de compresser et d'enregistrer les éléments à l'avance.

Avantages

  • La latence due à des niveaux de compression élevés n'est plus un problème. Il n'est plus nécessaire de compresser les fichiers à la volée, car ils peuvent désormais être récupérés directement.

Inconvénients

  • Les éléments doivent être compressés à chaque compilation. Les temps de compilation peuvent augmenter considérablement si des niveaux de compression élevés sont utilisés.

Compression statique avec Node et Express avec webpack

Étant donné que la compression statique implique de compresser les fichiers à l'avance, les paramètres webpack peuvent être modifiés pour compresser les éléments lors de l'étape de compilation. Pour ce faire, vous pouvez utiliser brotli-webpack-plugin.

Commencez par l'ajouter en tant que devDependency dans package.json :

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

Comme tout autre plug-in webpack, importez-le dans le fichier de configurations, webpack.config.js :

var path = require("path");

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

et l'inclure dans le tableau des plug-ins :

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

Le tableau de plug-ins utilise les arguments suivants :

  • asset : nom de l'asset cible.
  • [file] est remplacé par le nom de fichier de l'asset d'origine.
  • test : tous les éléments correspondant à cette expression régulière (c'est-à-dire les éléments JavaScript se terminant par .js) sont traités.

Par exemple, main.js serait renommé main.js.br.

Lorsque l'application se recharge et se reconstruit, une version compressée du bundle principal est désormais créée. Ouvrez la console Glitch pour voir ce qui se trouve dans le répertoire public/ final qui est diffusé par le serveur Node.

  1. Cliquez sur le bouton Outils.
  2. Cliquez sur le bouton Console.
  3. Dans la console, exécutez les commandes suivantes pour accéder au répertoire public et afficher tous ses fichiers :
cd public
ls -lh
Taille du bundle avec compression Brotli statique

La version compressée Brotli du bundle, main.bundle.js.br, est désormais également enregistrée ici et est environ 76 % plus petite (225 Ko contre 53 Ko) que main.bundle.js.

Ensuite, indiquez au serveur d'envoyer ces fichiers compressés au format Brotli chaque fois que leurs versions JS d'origine sont demandées. Pour ce faire, définissez un nouvel itinéraire dans server.js avant que les fichiers ne soient diffusés avec 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 est utilisé pour indiquer au serveur comment répondre à une requête GET pour un point de terminaison spécifique. Une fonction de rappel est ensuite utilisée pour définir comment gérer cette requête. Voici comment fonctionne le parcours :

  • Si vous spécifiez '*.js' comme premier argument, cela signifie que cela fonctionne pour tous les points de terminaison déclenchés pour récupérer un fichier JS.
  • Dans le rappel, .br est associé à l'URL de la requête et l'en-tête de réponse Content-Encoding est défini sur br.
  • L'en-tête Content-Type est défini sur application/javascript; charset=UTF-8 pour spécifier le type MIME.
  • Enfin, next() garantit que la séquence se poursuit avec tout rappel qui pourrait suivre.

Étant donné que certains navigateurs ne sont pas compatibles avec la compression Brotli, vérifiez que Brotli est pris en charge avant de renvoyer le fichier compressé avec Brotli. Pour ce faire, vérifiez que l'en-tête de requête Accept-Encoding inclut 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'));

Une fois l'application rechargée, examinez à nouveau le panneau "Réseau".

Taille du bundle de 53,1 Ko (contre 225 Ko)

Opération réussie ! Vous avez utilisé la compression Brotli pour compresser davantage vos composants.

Conclusion

Cet atelier de programmation a montré comment brotli peut réduire davantage la taille globale de votre application. Lorsqu'il est pris en charge, brotli est un algorithme de compression plus puissant que gzip.