Supprimer le code inutilisé

Dans cet atelier de programmation, vous allez améliorer les performances de l'application suivante en supprimant toutes les dépendances inutilisées et inutiles.

Capture d'écran de l'application

Mesurer

Il est toujours judicieux de commencer par mesurer les performances d'un site Web avant d'y ajouter des optimisations.

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

Vas-y, clique sur ton chaton préféré ! Realtime Database de Firebase est utilisé dans cette application. C'est pourquoi le score est mis à jour en temps réel et est synchronisé avec toutes les autres personnes qui utilisent l'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 Désactiver le cache.
  4. Actualisez l'application.

Taille du kit d'origine : 992 Ko

Près de 1 Mo de JavaScript est livré pour charger cette application simple !

Consultez les avertissements concernant le projet dans les outils de développement.

  • Cliquez sur l'onglet Console.
  • Assurez-vous que Warnings est activé dans le menu déroulant des niveaux à côté de l'entrée Filter.

Filtre "Avertissements"

  • Examinez l'avertissement affiché.

Avertissement concernant la console

Firebase, qui est l'une des bibliothèques utilisées dans cette application, est un bon samaritan en affichant un avertissement pour indiquer aux développeurs qu'ils ne doivent pas importer l'intégralité du package, mais uniquement les composants utilisés. En d'autres termes, vous pouvez supprimer des bibliothèques inutilisées dans cette application pour accélérer son chargement.

Dans certains cas, une bibliothèque particulière est utilisée, mais il existe une alternative plus simple. Le concept de suppression des bibliothèques inutiles est abordé plus loin dans ce tutoriel.

Analyser le bundle

L'application comporte deux dépendances principales:

  • Firebase: plate-forme qui fournit un certain nombre de services utiles pour les applications iOS, Android ou Web. Sa base de données en temps réel permet de stocker et de synchroniser en temps réel les informations sur chaque chaton.
  • Moment.js: bibliothèque d'utilitaires qui facilite la gestion des dates en JavaScript. La date de naissance de chaque chaton est stockée dans la base de données Firebase, et la valeur moment est utilisée pour calculer son âge en semaines.

Comment deux dépendances seulement peuvent-elles contribuer à une taille de bundle de presque 1 Mo ? L'une des raisons est que toute dépendance peut à son tour avoir ses propres dépendances. Il y en a donc beaucoup plus que deux si chaque profondeur/branche de "l'arborescence" de dépendances est prise en compte. Il est facile pour une application de devenir assez rapidement volumineux si de nombreuses dépendances sont incluses.

Analysez le bundler pour avoir une meilleure idée de ce qui se passe. De nombreux outils conçus par la communauté peuvent vous aider à y parvenir, tels que webpack-bundle-analyzer.

Le package de cet outil est déjà inclus dans l'application en tant que devDependency.

"devDependencies": {
  //...
  "webpack-bundle-analyzer": "^2.13.1"
},

Cela signifie qu'il peut être utilisé directement dans le fichier de configuration webpack. Importez-le au tout début de webpack.config.js:

const path = require("path");

//...
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
  .BundleAnalyzerPlugin;

Ajoutez-le maintenant en tant que plug-in à la fin du fichier, dans le tableau plugins:

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

Lorsque l'application est actualisée, vous devriez voir une visualisation de l'ensemble du bundle au lieu de l'application elle-même.

Analyseur de bundle Webpack

Pas aussi mignons que de voir des chatons comprenant un chat, mais incroyablement utile quand même. Lorsque vous pointez sur l'un des packages, sa taille est représentée de trois manières différentes:

Taille des statistiques Taille avant toute minimisation ou compression.
Taille analysée Taille du package réel dans le bundle après sa compilation. La version 4 de Webpack (utilisée dans cette application) réduit automatiquement la taille des fichiers compilés. C'est pourquoi elle est inférieure à la taille des statistiques.
Taille compressée avec GZIP Taille du package après avoir été compressé avec l'encodage gzip. Ce sujet est abordé dans un autre guide.

Avec l'outil d'analyse webpack-bundle-analyzer, il est plus facile d'identifier les packages inutilisés ou inutiles qui constituent un pourcentage élevé du bundle.

Supprimer les packages inutilisés

La visualisation montre que le package firebase consiste en bien plus qu'une simple base de données. Elle inclut des packages supplémentaires, tels que:

  • firestore
  • auth
  • storage
  • messaging
  • functions

Ce sont tous des services incroyables fournis par Firebase (et consultez la documentation pour en savoir plus), mais aucun d'entre eux n'est utilisé dans l'application. Il n'y a donc aucune raison de les importer tous.

Annulez les modifications dans webpack.config.js pour voir à nouveau l'application:

  • Supprimez BundleAnalyzerPlugin de la liste des plug-ins:
plugins: [
  //...
  new BundleAnalyzerPlugin()
];
  • À présent, supprimez l'importation inutilisée du haut du fichier:
const path = require("path");

//...
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

L'application devrait maintenant se charger normalement. Modifiez src/index.js pour mettre à jour les importations Firebase.

import firebase from 'firebase';
import firebase from 'firebase/app';
import 'firebase/database';

Désormais, l'avertissement "Outils de développement" ne s'affiche plus lorsque l'application s'actualise. L'ouverture du panneau Network (Réseau) de DevTools affiche également une bonne réduction de la taille du bundle:

Taille du bundle réduite à 480 Ko

Plus de la moitié de la taille du lot a été supprimée. Firebase fournit de nombreux services différents et permet aux développeurs de n'inclure que ceux qui sont réellement nécessaires. Dans cette application, seul firebase/database a été utilisé pour stocker et synchroniser toutes les données. L'importation firebase/app, qui configure la surface d'API pour chacun des différents services, est toujours requise.

De nombreuses autres bibliothèques populaires, telles que lodash, permettent également aux développeurs d'importer de manière sélective différentes parties de leurs packages. Si vous n'effectuez pas beaucoup de travail, mettre à jour les importations de bibliothèque dans une application pour n'inclure que ce qui est utilisé peut entraîner une amélioration significative des performances.

Bien que la taille du bundle ait considérablement diminué, il reste encore du travail. 😈

Suppression des packages inutiles

Contrairement à Firebase, l'importation de parties de la bibliothèque moment n'est pas aussi simple, mais peut-elle être entièrement supprimée ?

La date d'anniversaire de chaque chaton est stockée au format Unix (en millisecondes) dans la base de données Firebase.

Dates de naissance stockées au format Unix

Il s'agit de l'horodatage d'une date et d'une heure particulières représentées par le nombre de millisecondes écoulées depuis le 1er janvier 1970 à 00:00 UTC. Si la date et l'heure actuelles peuvent être calculées dans le même format, une petite fonction permettant de trouver l'âge de chaque chaton en semaines peut probablement être créée.

Comme toujours, essayez de ne pas copier et coller pendant que vous suivez cette procédure. Commencez par supprimer moment des importations dans src/index.js.

import firebase from 'firebase/app';
import 'firebase/database';
import * as moment from 'moment';

Un écouteur d'événements Firebase gère les modifications de valeur dans notre base de données:

favoritesRef.on("value", (snapshot) => { ... })

Au-dessus, ajoutez une petite fonction pour calculer le nombre de semaines à partir d'une date donnée:

const ageInWeeks = birthDate => {
  const WEEK_IN_MILLISECONDS = 1000 * 60 * 60 * 24 * 7;
  const diff = Math.abs((new Date).getTime() - birthDate);
  return Math.floor(diff / WEEK_IN_MILLISECONDS);
}

Dans cette fonction, la différence en millisecondes entre la date et l'heure actuelles (new Date).getTime() et la date de naissance (l'argument birthDate, déjà en millisecondes) est calculée et divisée par le nombre de millisecondes au cours d'une semaine unique.

Enfin, toutes les instances de moment peuvent être supprimées de l'écouteur d'événements en utilisant cette fonction à la place:

favoritesRef.on("value", (snapshot) => {
  const { kitties, favorites, names, birthDates } = snapshot.val();
  favoritesScores = favorites;

  kittiesList.innerHTML = kitties.map((kittiePic, index) => {
    const birthday = moment(birthDates[index]);

    return `
      <li>
        <img src=${kittiePic} onclick="favKittie(${index})">
        <div class="extra">
          <div class="details">
            <p class="name">${names[index]}</p>
            <p class="age">${moment().diff(birthday, 'weeks')} weeks old</p>
            <p class="age">${ageInWeeks(birthDates[index])} weeks old</p>
          </div>
          <p class="score">${favorites[index]} ❤</p>
        </div>
      </li>
    `})
});

À présent, actualisez l'application et revenez au panneau Network (Réseau).

Taille du bundle réduite à 225 Ko

La taille de notre lot a encore été réduite de plus de moitié !

Conclusion

Avec cet atelier de programmation, vous devriez comprendre comment analyser un bundle particulier et pourquoi il peut être si utile de supprimer les packages inutilisés ou inutiles. Avant de commencer à optimiser une application avec cette technique, il est important de savoir que celle-ci peut s'avérer beaucoup plus complexe dans les applications plus importantes.

En ce qui concerne la suppression des bibliothèques inutilisées, essayez d'identifier les parties d'un lot utilisées et celles qui ne le sont pas. Pour un package à l'apparence mystérieuse qui semble n'être utilisé nulle part, prenez du recul et vérifiez quelles dépendances de niveau supérieur pourraient en avoir besoin. Essayez de trouver un moyen de les dissocier l'un de l'autre.

Lorsqu'il s'agit de supprimer des bibliothèques inutiles, les choses peuvent être un peu plus compliquées. Il est important de travailler en étroite collaboration avec votre équipe et de voir s'il est possible de simplifier certaines parties du codebase. La suppression de moment dans cette application peut sembler être la bonne chose à chaque fois, mais que se passerait-il si des fuseaux horaires et différents paramètres régionaux devaient être gérés ? Ou que se passerait-il s'il y avait des manipulations de date plus compliquées ? La manipulation et l'analyse des dates et des heures peuvent être très complexes, et les bibliothèques telles que moment et date-fns simplifient considérablement ce processus.

Tout est un compromis, et il est important de déterminer si la complexité et les efforts liés au déploiement d'une solution personnalisée en valent la peine au lieu de s'appuyer sur une bibliothèque tierce.