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

Cet atelier de programmation explique comment réduire et compresser le code JavaScript pour l'application suivante améliore les performances de la page en réduisant la taille de la requête de l'application.

Capture d'écran de l'application

Mesurer

Avant de vous lancer dans l'ajout d'optimisations, il est toujours judicieux d'analyser l'état actuel de l'application.

  • Pour prévisualiser le site, appuyez sur Afficher l'application. Appuyez ensuite sur Plein écran plein écran

Cette application, qui a également été abordée dans la section , vous permet de voter pour celle que vous préférez chaton. 🐈

Voyons maintenant la taille de cette application:

  1. Appuyez sur Ctrl+Maj+J (ou Cmd+Option+J sur Mac) pour ouvrir les outils de développement.
  2. Cliquez sur l'onglet Réseau.
  3. Cochez la case Disable cache (Désactiver le cache).
  4. Actualisez l'application.

Taille d'origine du groupe dans le panneau "Réseau"

Bien que de nombreux progrès aient été réalisés dans la section Supprimer le code inutilisé, pour réduire la taille du bundle, 225 Ko reste assez volumineux.

Réduction

Prenons l'exemple du bloc de code suivant.

function soNice() {
  let counter = 0;

  while (counter < 100) {
    console.log('nice');
    counter++;
  }
}

Si cette fonction est enregistrée dans un fichier qui lui est propre, la taille du fichier est d'environ 112 Go (octets).

Si tous les espaces sont supprimés, le code obtenu se présente comme suit:

function soNice(){let counter=0;while(counter<100){console.log("nice");counter++;}}

La taille du fichier est maintenant d'environ 83 octets. S'il s'entremêle encore plus en réduisant la longueur du nom de la variable et en modifiant certaines expressions, le code final peut finissent par ressembler à ceci:

function soNice(){for(let i=0;i<100;)console.log("nice"),i++}

La taille du fichier atteint désormais 62 octets.

À chaque étape, le code devient plus difficile à lire. Toutefois, Le moteur JavaScript interprète chacun de ces éléments exactement de la même manière. La l'avantage d'obscurcir le code de cette manière peut contribuer à réduire la taille différentes tailles d'écran. 112 M n'était vraiment pas grand-chose au départ, mais il y avait quand même de moins de taille !

Dans cette application, la version 4 de webpack est utilisée comme module bundler. La version spécifique est visible dans package.json.

"devDependencies": {
  //...
  "webpack": "^4.16.4",
  //...
}

La version 4 réduit déjà la taille du bundle par défaut en mode production. Il utilise TerserWebpackPlugin est un plug-in pour Terser. Terser est un outil couramment utilisé pour compresser du code JavaScript.

Pour voir à quoi ressemble le code réduit, cliquez sur main.bundle.js dans le panneau Network (Réseau) des outils de développement. Cliquez ensuite sur le bouton Onglet Response (Réponse).

Réponse réduite

Le code dans sa forme finale, réduit et tronqué, est affiché dans le corps de la réponse. Pour connaître la taille du bundle sans réduction, ouvrez webpack.config.js et mettez à jour la configuration mode.

module.exports = {
  mode: 'production',
  mode: 'none',
  //...

Actualisez l'application et examinez à nouveau la taille du bundle à l'aide de la Panneau Network (Outils de développement)

Taille du bundle de 767 Ko

C'est une grande différence ! 😅

Veillez à annuler les modifications avant de continuer.

module.exports = {
  mode: 'production',
  mode: 'none',
  //...

L'ajout d'un processus de réduction de la taille du code dans votre application dépend des outils disponibles que vous utilisez:

  • Si vous utilisez webpack v4 ou une version ultérieure, aucune action supplémentaire n'est requise de votre part. car la taille du code est réduite par défaut en mode production. 👍
  • Si une version plus ancienne de webpack est utilisée, installez et incluez TerserWebpackPlugin. au processus de compilation Webpack. La documentation explique cela en détail.
  • D'autres plug-ins de minimisation existent également et peuvent être utilisés à la place, tel que BabelMinifyWebpackPlugin et ClosureCompilerPlugin.
  • Si un bundler de module n'est pas utilisé du tout, utilisez Terser. en tant qu’outil CLI ou de l’inclure directement en tant que dépendance.

Compression

Bien que le terme « compression » est parfois vaguement utilisé pour expliquer comment le code est est réduite lors du processus de minimisation, elle n'est pas compressée au sens littéral du terme.

La compression fait généralement référence au code qui a été modifié à l'aide d'un l'algorithme de compression. Contrairement à la minimisation, qui finit par fournir code valide, le code compressé doit être décompressé avant d'être utilisé.

À chaque requête et réponse HTTP, les navigateurs et les serveurs Web peuvent ajouter en-têtes à inclure des informations supplémentaires sur l'élément récupéré ou reçu. Il peut s'agir dans l'onglet Headers du panneau "DevTools Network", où trois types sont affichées:

  • General (Général) représente les en-têtes généraux pertinents pour l'ensemble de la requête/réponse d'interaction.
  • Le champ Response Headers (En-têtes de réponse) contient une liste d'en-têtes spécifiques à la réponse. à partir du serveur.
  • Request Headers (En-têtes de requête) contient la liste des en-têtes joints à la requête par client.

Examinez l'en-tête accept-encoding dans Request Headers.

Accepter l&#39;en-tête d&#39;encodage

accept-encoding permet au navigateur de spécifier le contenu des formats d'encodage ou des algorithmes de compression qu'il prend en charge. Il existe de nombreux de compression de texte, mais seuls trois sont ici pour la compression (et la décompression) des requêtes réseau HTTP:

  • Gzip (gzip): la compression la plus utilisée pour les interactions avec le serveur et le client. Il s'appuie sur l'API Deflate et est pris en charge par tous les navigateurs actuels.
  • Deflate (deflate): peu utilisé.
  • Brotli (br): une compression plus récente qui vise à améliorer davantage les taux de compression, ce qui peut entraîner les pages se chargent encore plus vite. Il est compatible avec les dernières versions de la plupart des navigateurs.

L'exemple d'application présenté dans ce tutoriel est identique à celui présenté dans l'atelier Supprimer le code inutilisé, sauf que Express est désormais utilisé comme framework de serveur. Dans quelques sections, nous nous pencherons sur la compression statique et dynamique.

Compression dynamique

La compression dynamique consiste à compresser les éléments à la volée, au fur et à mesure demandé par le navigateur.

Avantages

  • Il n'est pas nécessaire de créer ni de mettre à jour des versions compressées enregistrées des éléments terminé.
  • La compression à la volée fonctionne particulièrement bien pour les pages Web générés dynamiquement.

Inconvénients

  • Compression des fichiers à des niveaux supérieurs pour obtenir de meilleurs taux de compression prend plus de temps. Cela peut entraîner une perte de performances, car l'utilisateur attend que les éléments soient compresser avant qu'ils ne soient envoyés par le serveur.

Compression dynamique avec Node/Express

Le fichier server.js est chargé de configurer le serveur de nœuds 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);
});

Actuellement, cela consiste à importer express et à utiliser le express.static pour charger tous les fichiers HTML, JS et CSS statiques public/ (ces fichiers sont créés par webpack à chaque build).

Pour vous assurer que tous les éléments sont compressés à chaque demande, compression vous permet être utilisée. Commencez par l'ajouter en tant que devDependency dans package.json:

"devDependencies": {
  //...
  "compression": "^1.7.3"
},

Importez-le ensuite dans le fichier serveur server.js:

const express = require('express');
const compression = require('compression');

Ajoutez-le en tant que middleware avant l'installation de express.static:

//...

const app = express();

app.use(compression());

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

//...

Maintenant, actualisez l'application et examinez la taille du bundle dans le panneau Network (Réseau).

Taille du bundle avec compression dynamique

De 225 Ko à 61,6 Ko Actuellement, dans Response Headers, un content-encoding indique que le serveur envoie ce fichier encodé avec gzip.

En-tête d&#39;encodage du contenu

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 une préoccupation. Rien ne doit se produire à la volée pour compresser les fichiers, car ils peuvent désormais être récupérés directement.

Inconvénients

  • Les éléments doivent être compressés à chaque compilation. Les durées de compilation peuvent augmenter de manière significative si des niveaux de compression élevés sont utilisés.

Compression statique avec Node/Express et webpack

La compression statique implique de compresser des fichiers à l'avance. peuvent être modifiés pour compresser les éléments lors de l'étape de compilation. CompressionPlugin pour cela.

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

"devDependencies": {
  //...
  "compression-webpack-plugin": "^1.1.11"
},

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

const path = require("path");

//...

const CompressionPlugin = require("compression-webpack-plugin");

Et incluez-le dans le tableau plugins:

module.exports = {
  //...
  plugins: [
    //...
    new CompressionPlugin()
  ]
}

Par défaut, le plug-in compresse les fichiers de compilation à l'aide de gzip. Jetez un coup d'œil consultez la documentation pour découvrir comment ajouter des options pour utiliser un autre algorithme ou inclure/exclure certains fichiers.

Lorsque l'application est actualisée et recréée, une version compressée du bundle principal est à présent créé. Ouvrez la console Glitch pour voir le contenu le répertoire final public/ diffusé par le serveur Node.

  • Cliquez sur le bouton Tools (Outils).
  • Cliquez sur le bouton Console.
  • Dans la console, exécutez les commandes suivantes pour passer à public et voir tous ses fichiers:
cd public
ls

Fichiers finaux générés dans le répertoire public

La version compressée du bundle, main.bundle.js.gz, est maintenant enregistrée ici sous le nom bien. CompressionPlugin compresse également index.html par défaut.

La prochaine chose à faire est de demander au serveur d'envoyer ces fichiers compressés avec gzip chaque fois que leur version JS originale est demandée. Cela peut être fait en définissant une nouvelle route 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 + '.gz';
  res.set('Content-Encoding', 'gzip');
  next();
});

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

//...

app.get est utilisé pour indiquer au serveur comment répondre à une demande GET pour une un point de terminaison spécifique. Une fonction de rappel est ensuite utilisée pour définir la manière de gérer ce requête. L'itinéraire fonctionne de la manière suivante:

  • Si vous spécifiez '*.js' comme premier argument, cela fonctionne pour chaque qui est déclenché pour récupérer un fichier JS.
  • Dans le rappel, .gz est associé à l'URL de la requête. L'en-tête de réponse Content-Encoding est défini sur gzip.
  • Enfin, next() garantit que la séquence continue à n'importe quel rappel. qui pourraient être la prochaine.

Une fois l'application actualisée, consultez à nouveau le panneau Network.

Réduction de la taille de bundle avec la compression statique

Comme précédemment, la taille du lot a été nettement réduite !

Conclusion

Cet atelier de programmation a abordé le processus de minimisation et de compression du code source. Ces deux techniques sont en train de devenir utilisées par défaut dans de nombreux outils disponibles aujourd'hui. Il est donc important de déterminer si votre chaîne d'outils les prend en charge ou si vous devriez commencer à appliquer les deux processus vous-même.