Rimuovi il codice inutilizzato

Houssein Djirdeh
Houssein Djirdeh

In questo codelab, migliora le prestazioni della seguente applicazione rimuovendo le dipendenze inutilizzate e non necessarie.

Screenshot dell'app

Misura

È sempre una buona idea misurare prima le prestazioni di un sito web prima di aggiungere ottimizzazioni.

  • Per visualizzare l'anteprima del sito, premi Visualizza app. Quindi premi Schermo intero schermo intero.

Fai clic sul tuo gattino preferito. In questa applicazione viene utilizzato il Realtime Database di Firebase, motivo per cui il punteggio viene aggiornato in tempo reale e sincronizzato con tutti gli altri utenti che utilizzano l'applicazione. 🐈

  1. Premi "Control+Maiusc+J" (o "Command+Opzione+J" su Mac) per aprire DevTools.
  2. Fai clic sulla scheda Rete.
  3. Seleziona la casella di controllo Disattiva cache.
  4. Ricarica l'app.

Dimensioni originali del bundle di 992 KB

Per caricare questa semplice applicazione vengono inviati quasi 1 MB di JavaScript.

Dai un'occhiata agli avvisi del progetto in DevTools.

  • Fai clic sulla scheda Console.
  • Assicurati che Warnings sia abilitato nel menu a discesa dei livelli accanto all'input Filter.

Filtro Avvisi

  • Dai un'occhiata all'avviso visualizzato.

Avviso della console

Firebase, una delle librerie utilizzate in questa applicazione, si sta comportando da buon samaritano fornendo un avviso per informare gli sviluppatori di non importare l'intero pacchetto, ma solo i componenti utilizzati. In altre parole, in questa applicazione sono presenti librerie inutilizzate che possono essere rimosse per velocizzare il caricamento.

Esistono anche casi in cui viene utilizzata una determinata libreria, ma in cui potrebbe esserci un'alternativa più semplice. Il concetto di rimozione delle librerie non necessarie viene esplorato più avanti in questo tutorial.

Analisi del bundle

Nell'applicazione esistono due dipendenze principali:

  • Firebase: una piattaforma che fornisce una serie di servizi utili per applicazioni iOS, Android o web. Qui viene utilizzato Realtime Database per archiviare e sincronizzare le informazioni per ogni gattino in tempo reale.
  • Moment.js: una libreria di utilità che semplifica la gestione delle date in JavaScript. La data di nascita di ogni gattino viene memorizzata nel database Firebase e moment viene utilizzata per calcolare la sua età in settimane.

In che modo due sole dipendenze possono contribuire a una dimensione del bundle di quasi 1 MB? Uno dei motivi è che qualsiasi dipendenza può a sua volta avere le proprie dipendenze, quindi ce ne sono molte di più di due se si considera ogni livello/ramo dell'"albero" delle dipendenze. È facile che un'applicazione diventi grande in tempi relativamente brevi se vengono incluse molte dipendenze.

Analizza il bundler per farti un'idea più precisa di cosa sta succedendo. Esistono diversi strumenti creati dalla community che possono aiutarti a farlo, come webpack-bundle-analyzer.

Il pacchetto per questo strumento è già incluso nell'app come devDependency.

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

Ciò significa che può essere utilizzato direttamente nel file di configurazione webpack. Importalo all'inizio di webpack.config.js:

const path = require("path");

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

Ora aggiungilo come plug-in alla fine del file all'interno dell'array plugins:

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

Quando l'applicazione viene ricaricata, dovresti vedere una visualizzazione dell'intero bundle anziché dell'app stessa.

Webpack Bundle Analyzer

Non è carino come vedere dei gattini 🐱, ma è comunque molto utile. Se passi il mouse sopra uno dei pacchetti, le sue dimensioni vengono visualizzate in tre modi diversi:

Dimensioni delle statistiche Dimensioni prima di qualsiasi riduzione o compressione.
Dimensioni analizzate Dimensioni del pacchetto effettivo all'interno del bundle dopo la compilazione. La versione 4 di webpack (utilizzata in questa applicazione) comprime automaticamente i file compilati, motivo per cui le dimensioni sono inferiori a quelle delle statistiche.
Dimensioni compresse con Gzip Dimensioni del pacchetto dopo la compressione con la codifica gzip. Questo argomento è trattato in una guida separata.

Con lo strumento webpack-bundle-analyzer, è più facile identificare i pacchetti inutilizzati o non necessari che costituiscono una percentuale elevata del bundle.

Rimozione dei pacchetti inutilizzati

La visualizzazione mostra che il pacchetto firebase è composto da un lotto di elementi oltre a un database. Sono inclusi pacchetti aggiuntivi come:

  • firestore
  • auth
  • storage
  • messaging
  • functions

Si tratta di servizi straordinari forniti da Firebase (consulta la documentazione per saperne di più), ma nessuno di questi viene utilizzato nell'applicazione, quindi non c'è alcun motivo per importarli tutti.

Ripristina le modifiche in webpack.config.js per visualizzare di nuovo l'applicazione:

  • Rimuovi BundleAnalyzerPlugin dall'elenco dei plug-in:
plugins: [
  //...
  new BundleAnalyzerPlugin()
];
  • Ora rimuovi l'importazione inutilizzata dalla parte superiore del file:
const path = require("path");

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

Ora l'applicazione dovrebbe caricarsi normalmente. Modifica src/index.js per aggiornare le importazioni Firebase.

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

Ora, quando l'app viene ricaricata, l'avviso di DevTools non viene visualizzato. L'apertura del riquadro Rete di DevTools mostra anche una bella riduzione delle dimensioni del bundle:

Dimensioni del bundle ridotte a 480 KB

È stata rimossa più della metà delle dimensioni del pacchetto. Firebase fornisce molti servizi diversi e offre agli sviluppatori la possibilità di includere solo quelli effettivamente necessari. In questa applicazione, solo firebase/database è stato utilizzato per archiviare e sincronizzare tutti i dati. L'importazione di firebase/app, che configura la superficie API per ciascuno dei diversi servizi, è sempre obbligatoria.

Molte altre librerie popolari, come lodash, consentono inoltre agli sviluppatori di importare selettivamente diverse parti dei pacchetti. Senza fare molto lavoro, l'aggiornamento delle importazioni di librerie in un'applicazione per includere solo ciò che viene utilizzato può comportare miglioramenti significativi delle prestazioni.

Sebbene le dimensioni del bundle siano state ridotte notevolmente, c'è ancora molto lavoro da fare. 😈

Rimozione dei pacchetti non necessari

A differenza di Firebase, l'importazione di parti della libreria moment non può essere eseguita con facilità, ma forse può essere rimossa completamente.

La data di nascita di ogni gattino carino è memorizzata in formato Unix (millisecondi) nel database Firebase.

Date di nascita memorizzate in formato Unix

Questo è un timestamp di una data e un'ora specifiche rappresentate dal numero di millisecondi trascorsi dal 1° gennaio 1970 alle 00:00 UTC. Se la data e l'ora attuali possono essere calcolate nello stesso formato, è possibile creare una piccola funzione per trovare l'età di ogni gattino in settimane.

Come sempre, cerca di non copiare e incollare mentre segui le istruzioni. Inizia rimuovendo moment dalle importazioni in src/index.js.

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

Esiste un listener di eventi Firebase che gestisce le modifiche ai valori nel nostro database:

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

Sopra, aggiungi una piccola funzione per calcolare il numero di settimane a partire da una data specifica:

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

In questa funzione, la differenza in millisecondi tra la data e l'ora attuali (new Date).getTime() e la data di nascita (l'argomento birthDate, già in millisecondi) viene calcolata e divisa per il numero di millisecondi in una settimana.

Infine, tutte le istanze di moment possono essere rimosse nel listener di eventi utilizzando questa funzione:

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

Ora ricarica l'applicazione e dai un'altra occhiata al riquadro Rete.

Dimensioni del bundle ridotte a 225 KB

Le dimensioni del nostro bundle sono state ridotte di oltre la metà.

Conclusione

Con questo codelab, dovresti avere una buona comprensione di come analizzare un bundle specifico e perché può essere così utile rimuovere pacchetti inutilizzati o non necessari. Prima di iniziare a ottimizzare un'applicazione con questa tecnica, è importante sapere che può essere molto più complessa nelle applicazioni più grandi.

Per quanto riguarda la rimozione delle librerie inutilizzate, cerca di scoprire quali parti di un bundle vengono utilizzate e quali no. Per un pacchetto dall'aspetto misterioso che sembra non essere utilizzato da nessuna parte, fai un passo indietro e controlla quali dipendenze di primo livello potrebbero averne bisogno. Cerca un modo per separarli.

Per quanto riguarda la rimozione delle librerie non necessarie, le cose possono essere un po' più complicate. È importante collaborare a stretto contatto con il tuo team e verificare se è possibile semplificare parti del codice sorgente. Rimuovere moment in questa applicazione potrebbe sembrare la cosa giusta da fare ogni volta, ma cosa succederebbe se ci fossero fusi orari e impostazioni internazionali diverse da gestire? O cosa succederebbe se ci fossero manipolazioni di date più complicate? Le cose possono diventare molto complicate quando si manipolano e analizzano date/ore e librerie come moment e date-fns semplificano notevolmente questa operazione.

Tutto è un compromesso ed è importante valutare se valga la pena la complessità e l'impegno per implementare una soluzione personalizzata anziché affidarsi a una libreria di terze parti.