Riduci i payload JavaScript con la suddivisione del codice

Houssein Djirdeh
Houssein Djirdeh

La maggior parte delle pagine web e delle applicazioni è composta da molte parti diverse. Anziché inviare tutto il codice JavaScript che compone l'applicazione non appena viene caricata la prima pagina, la suddivisione del codice JavaScript in più blocchi migliora le prestazioni della pagina.

Questo codelab mostra come utilizzare la divisione del codice per migliorare il rendimento di un'applicazione semplice che ordina tre numeri.

Una finestra del browser mostra un'applicazione denominata Magic Sorter con tre campi per l'inserimento di numeri e un pulsante di ordinamento.

Misura

Come sempre, è importante misurare prima le prestazioni di un sito web prima di tentare di aggiungere ottimizzazioni.

  1. Per visualizzare l'anteprima del sito, premi Visualizza app. Quindi premi Schermo intero schermo intero.
  2. Premi "Control+Maiusc+J" (o "Command+Opzione+J" su Mac) per aprire DevTools.
  3. Fai clic sulla scheda Rete.
  4. Seleziona la casella di controllo Disattiva cache.
  5. Ricarica l'app.

Il riquadro Rete mostra il bundle JavaScript di 71,2 KB.

71,2 KB di JavaScript solo per ordinare alcuni numeri in una semplice applicazione. What gives?

Nel codice sorgente (src/index.js), la libreria lodash viene importata e utilizzata in questa applicazione. Lodash fornisce molte funzioni di utilità utili, ma qui viene utilizzato un solo metodo del pacchetto. L'installazione e l'importazione di intere dipendenze di terze parti, di cui viene utilizzata solo una piccola parte, è un errore comune.

Ottimizza

Esistono diversi modi per ridurre le dimensioni del bundle:

  1. Scrivere un metodo di ordinamento personalizzato anziché importare una libreria di terze parti
  2. Utilizza il metodo Array.prototype.sort() integrato per ordinare numericamente
  3. Importa solo il metodo sortBy da lodash e non l'intera libreria
  4. Scarica il codice per l'ordinamento solo quando l'utente fa clic sul pulsante

Le opzioni 1 e 2 sono metodi perfettamente appropriati per ridurre le dimensioni del bundle (e probabilmente sono le più sensate per un'applicazione reale). Tuttavia, non vengono utilizzati in questo tutorial per motivi didattici 😈.

Le opzioni 3 e 4 contribuiscono a migliorare le prestazioni di questa applicazione. Le sezioni successive di questo codelab riguardano questi passaggi. Come per qualsiasi tutorial di programmazione, prova sempre a scrivere il codice da solo invece di copiarlo e incollarlo.

Importa solo ciò che ti serve

Alcuni file devono essere modificati per importare solo il singolo metodo da lodash. Per iniziare, sostituisci questa dipendenza in package.json:

"lodash": "^4.7.0",

con questo:

"lodash.sortby": "^4.7.0",

Ora, in src/index.js, importa questo modulo specifico:

import "./style.css";
import _ from "lodash";
import sortBy from "lodash.sortby";

e aggiorna la modalità di ordinamento dei valori:

form.addEventListener("submit", e => {
  e.preventDefault();
  const values = [input1.valueAsNumber, input2.valueAsNumber, input3.valueAsNumber];
  const sortedValues = _.sortBy(values);
  const sortedValues = sortBy(values);

  results.innerHTML = `
    <h2>
      ${sortedValues}
    </h2>
  `
});

Ricarica l'applicazione, apri DevTools e dai un'altra occhiata al riquadro Rete.

Il riquadro Rete mostra il bundle JavaScript di 15,2 KB.

Per questa applicazione, le dimensioni del bundle sono state ridotte di oltre 4 volte con un lavoro minimo, ma c'è ancora spazio per miglioramenti.

Suddivisione del codice

webpack è uno dei bundler di moduli open source più popolari utilizzati oggi. In breve, raggruppa tutti i moduli JavaScript (e altri asset) che compongono un'applicazione web in file statici che possono essere letti dal browser.

Il singolo bundle utilizzato in questa applicazione può essere suddiviso in due blocchi separati:

  • Uno responsabile del codice che compone il nostro percorso iniziale
  • Un blocco secondario che contiene il nostro codice di ordinamento

Con l'utilizzo delle importazioni dinamiche, un chunk secondario può essere caricato in modalità differita o caricato su richiesta. In questa applicazione, il codice che compone il chunk può essere caricato solo quando l'utente preme il pulsante.

Inizia rimuovendo l'importazione di primo livello per il metodo di ordinamento in src/index.js:

import sortBy from "lodash.sortby";

e importalo all'interno del listener di eventi che si attiva quando viene premuto il pulsante:

form.addEventListener("submit", e => {
  e.preventDefault();
  import('lodash.sortby')
    .then(module => module.default)
    .then(sortInput())
    .catch(err => { alert(err) });
});

La funzionalità import() fa parte di una proposta (attualmente alla fase 3 della procedura TC39) per includere la possibilità di importare dinamicamente un modulo. webpack ha già incluso il supporto per questa funzionalità e segue la stessa sintassi stabilita dalla proposta.

import() restituisce una promessa e, quando viene risolta, viene fornito il modulo selezionato, che viene suddiviso in un blocco separato. Dopo la restituzione del modulo, module.default viene utilizzato per fare riferimento all'esportazione predefinita fornita da lodash. La promessa è concatenata a un'altra .then che chiama un metodo sortInput per ordinare i tre valori di input. Alla fine della catena di promesse, .catch() viene utilizzato per gestire i casi in cui la promessa viene rifiutata a causa di un errore.

L'ultima cosa da fare è scrivere il metodo sortInput alla fine del file. Deve essere una funzione che restituisce una funzione che accetta il metodo importato da lodash.sortBy. La funzione nidificata può quindi ordinare i tre valori di input e aggiornare il DOM.

const sortInput = () => {
  return (sortBy) => {
    const values = [
      input1.valueAsNumber,
      input2.valueAsNumber,
      input3.valueAsNumber
    ];
    const sortedValues = sortBy(values);

    results.innerHTML = `
      <h2>
        ${sortedValues}
      </h2>
    `
  };
}

Monitoraggio

Ricarica l'applicazione un'ultima volta e tieni d'occhio il riquadro Rete. Viene scaricato solo un piccolo bundle iniziale non appena l'app viene caricata.

Il riquadro Rete mostra il bundle JavaScript di 2,7 KB.

Dopo aver premuto il pulsante per ordinare i numeri inseriti, viene recuperato ed eseguito il blocco che contiene il codice di ordinamento.

Il riquadro Rete mostra un bundle JavaScript di 2,7 KB seguito da un bundle JavaScript di 13,9 KB.

Nota come i numeri vengono comunque ordinati.

Conclusione

La suddivisione del codice e il caricamento differito possono essere tecniche estremamente utili per ridurre le dimensioni iniziali del bundle dell'applicazione, il che può comportare direttamente tempi di caricamento della pagina molto più rapidi. Tuttavia, prima di includere questa ottimizzazione nella tua applicazione, devi considerare alcuni aspetti importanti.

UI con caricamento lento

Quando carichi in modalità differita moduli di codice specifici, è importante considerare l'esperienza degli utenti con connessioni di rete più deboli. La suddivisione e il caricamento di una parte di codice molto grande quando un utente invia un'azione può far sembrare che l'applicazione abbia smesso di funzionare, quindi valuta la possibilità di mostrare un indicatore di caricamento di qualche tipo.

Caricamento lento dei moduli dei nodi di terze parti

Il caricamento differito delle dipendenze di terze parti nell'applicazione non è sempre l'approccio migliore e dipende da dove le utilizzi. In genere, le dipendenze di terze parti vengono suddivise in un bundle vendor separato che può essere memorizzato nella cache poiché non vengono aggiornate spesso. Scopri di più su come SplitChunksPlugin può aiutarti a farlo.

Caricamento lento con un framework JavaScript

Molti framework e librerie popolari che utilizzano webpack forniscono astrazioni per semplificare il caricamento differito rispetto all'utilizzo di importazioni dinamiche al centro dell'applicazione.

Sebbene sia utile capire come funzionano le importazioni dinamiche, utilizza sempre il metodo consigliato dal framework/dalla libreria per caricare in modo differito moduli specifici.

Precaricamento e prefetching

Se possibile, sfrutta i suggerimenti del browser come <link rel="preload"> o <link rel="prefetch"> per provare a caricare i moduli critici ancora prima. webpack supporta entrambi i suggerimenti tramite l'uso di commenti magici nelle istruzioni import. Questo aspetto viene spiegato in dettaglio nella guida Precaricare i chunk critici.

Caricamento lento di più del codice

Le immagini possono costituire una parte significativa di un'applicazione. Il caricamento lento di quelli sotto la piega o al di fuori dell'area visibile del dispositivo può velocizzare un sito web. Scopri di più in merito nella guida Lazysizes.