In questo codelab, migliora le prestazioni della seguente applicazione rimuovendo le dipendenze inutilizzate e non necessarie.
Misura
È sempre buona prassi misurare prima il rendimento di un sito web prima di aggiungere le ottimizzazioni.
- Per visualizzare l'anteprima del sito, premi Visualizza app, quindi premi A schermo intero .
Fai clic sul tuo gattino preferito. In questa applicazione viene utilizzato il Realtime Database di Firebase, motivo per cui il punteggio si aggiorna in tempo reale e viene sincronizzato con tutte le altre persone che utilizzano l'applicazione. 🐈
- Premi "Control+Maiusc+J" (o "Comando+Opzione+J" su Mac) per aprire DevTools.
- Fai clic sulla scheda Rete.
- Seleziona la casella di controllo Disattiva cache.
- Ricarica l'app.
Per caricare questa semplice applicazione viene inviato quasi 1 MB di codice JavaScript.
Dai un'occhiata agli avvisi del progetto in DevTools.
- Fai clic sulla scheda Console.
- Assicurati che
Warnings
sia attivato nel menu a discesa dei livelli accanto all'inputFilter
.
- Dai un'occhiata all'avviso visualizzato.
Firebase, una delle librerie utilizzate in questa applicazione, si comporta da buon samaritano fornendo un avviso per segnalare agli sviluppatori di non importare l'intero pacchetto, ma solo i componenti utilizzati. In altre parole, esistono librerie non utilizzate che possono essere rimosse in questa applicazione per velocizzarne il caricamento.
Esistono anche casi in cui viene utilizzata una determinata libreria, ma potrebbe esserci un'alternativa più semplice. Il concetto di rimozione delle librerie non necessarie viene approfondito più avanti in questo tutorial.
Analisi del bundle
L'applicazione ha due dipendenze principali:
- Firebase: una piattaforma che fornisce una serie di servizi utili per applicazioni web, Android o iOS. Qui il Database in tempo reale viene utilizzato per archiviare e sincronizzare le informazioni di ciascun 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 utilizzato per calcolarne l'età in settimane.
Come possono solo due dipendenze contribuire a un pacchetto di dimensioni quasi 1 MB? Uno dei motivi è che qualsiasi dipendenza può avere a sua volta le proprie dipendenze, quindi ce ne sono molte di più se si considera ogni profondità/ramo della "pianta" delle dipendenze. È facile per un'applicazione diventare di grandi dimensioni in un periodo di tempo relativamente breve se sono incluse molte dipendenze.
Analizza il pacchettizzatore per avere un'idea più chiara di cosa sta succedendo. Esistono diversi strumenti creati dalla community che possono aiutarti a farlo, ad esempio webpack-bundle-analyzer
.
Il pacchetto di 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 di 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.
Non è così carino come vedere dei gattini 🐱, ma è comunque incredibilmente utile. Se passi il mouse sopra uno dei pacchetti, ne vengono visualizzate le dimensioni in tre modi diversi:
Dimensioni delle statistiche | Dimensioni prima di qualsiasi miniaturizzazione o compressione. |
---|---|
Dimensioni analizzate | Dimensioni del pacchetto effettivo all'interno del bundle dopo la compilazione. La versione 4 di webpack (utilizzata in questa applicazione) riduce automaticamente in dimensioni minime i file compilati, motivo per cui sono più piccoli delle dimensioni riportate nelle statistiche. |
Dimensioni compresse con gzip | Dimensioni del pacchetto dopo la compressione con 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 grande percentuale del bundle.
Rimozione dei pacchetti inutilizzati
La visualizzazione mostra che il pacchetto firebase
è costituito da molto più di 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'è motivo di 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;
L'applicazione dovrebbe caricarsi normalmente. Modifica src/index.js
per aggiornare le importazioni di 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 buona riduzione delle dimensioni del bundle:
È stata rimossa più della metà delle dimensioni del pacchetto. Firebase offre molti servizi diversi e consente agli sviluppatori di includere solo quelli di cui hanno effettivamente bisogno. In questa applicazione è stato utilizzato solo firebase/database
per archiviare e sincronizzare tutti i dati. L'importazione firebase/app
, che configura l'interfaccia API per ciascuno dei diversi servizi, è sempre obbligatoria.
Molte altre librerie popolari, come lodash
, consentono inoltre agli sviluppatori di
importare selettivamente parti diverse dei loro pacchetti. Senza fare molto,
l'aggiornamento delle importazioni delle librerie in un'applicazione in modo da includere solo ciò che viene utilizzato
può comportare miglioramenti significativi delle prestazioni.
Sebbene le dimensioni del bundle siano state ridotte notevolmente, c'è ancora molto da fare. 😈
Rimozione dei pacchetti non necessari
A differenza di Firebase, l'importazione di parti della libreria moment
non può essere eseguita così facilmente, ma forse può essere rimossa del tutto?
Il compleanno di ogni grazioso gattino viene memorizzato in formato Unix (millisecondi) nel database Firebase.
Si tratta di un timestamp di una data e un'ora specifiche rappresentato dal numero di millisecondi trascorsi dal 1° gennaio 1970 00:00 UTC. Se la data e l'ora correnti possono essere calcolate nello stesso formato, probabilmente è possibile creare una piccola funzione per trovare l'età di ogni gattino in settimane.
Come sempre, cerca di non copiare e incollare mentre segui la procedura. Inizia
rimuovendo moment
dalle importazioni in src/index.js
.
import firebase from 'firebase/app';
import 'firebase/database';
import * as moment from 'moment';
Esiste un gestore di eventi Firebase che gestisce le modifiche dei valori nel nostro database:
favoritesRef.on("value", (snapshot) => { ... })
Sopra, aggiungi una piccola funzione per calcolare il numero di settimane 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 la
ora corrente (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
singola settimana.
Infine, tutte le istanze di moment
possono essere rimosse nell'ascoltatore 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.
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 determinato bundle e del motivo per cui può essere così utile rimuovere i pacchetti inutilizzati o non necessari. Prima di iniziare a ottimizzare un'applicazione con questa tecnica, è importante sapere che questa operazione può essere molto più complessa nelle applicazioni più grandi.
In merito alla rimozione delle librerie non utilizzate, prova a scoprire quali parti di un bundle vengono utilizzate e quali no. Se un pacchetto sembra misterioso e non viene utilizzato da nessuna parte, fai un passo indietro e controlla quali dipendenze di primo livello potrebbero averne bisogno. Prova a trovare un modo per disaccoppiarli.
Quando si tratta di rimuovere le librerie non necessarie, le cose possono essere un po' più complicate. È importante collaborare strettamente con il team per capire se è possibile semplificare parti della base di codice. La rimozione di moment
in questa
applicazione potrebbe sembrare la cosa giusta da fare ogni volta, ma cosa succederebbe
se fossero presenti fusi orari e impostazioni internazionali diversi da gestire? O se
esistessero manipolazioni delle date più complesse? Le cose possono diventare molto difficili quando si manipolano e analizzano date/orari e librerie come moment
e date-fns
semplificano notevolmente questa operazione.
Ogni cosa comporta un compromesso ed è importante valutare se valga la pena di affrontare la complessità e lo sforzo di implementare una soluzione personalizzata anziché affidarsi a una libreria di terze parti.