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 suddivisione del codice per migliorare le prestazioni di una semplice applicazione che ordina tre numeri.

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

Misura

Come sempre, è importante misurare innanzitutto il rendimento 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 "Ctrl+Maiusc+J" (o "Cmd+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.

Riquadro Rete che mostra un bundle JavaScript da 71,2 kB.

71,2 kB di JavaScript solo per ordinare alcuni numeri in una semplice applicazione. Che succede?

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 alcuni modi per ridurre le dimensioni del bundle:

  1. Scrivi un metodo di ordinamento personalizzato anziché importare una libreria di terze parti
  2. Utilizza il metodo integrato Array.prototype.sort() per ordinare i dati in base ai numeri
  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 avrebbero più senso per un'applicazione reale). Tuttavia, non vengono utilizzati in questo tutorial per motivi didattici 😈.

Sia l'opzione 3 che l'opzione 4 contribuiscono a migliorare le prestazioni di questa applicazione. Le prossime sezioni di questo codelab illustrano questi passaggi. Come per qualsiasi tutorial di programmazione, prova sempre a scrivere il codice autonomamente anziché 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 il modo in cui i valori vengono ordinati:

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'occhiata di nuovo al riquadro Rete.

Riquadro Rete che mostra un bundle JavaScript da 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 ulteriori miglioramenti.

Suddivisione del codice

webpack è uno dei bundler di moduli open source più popolari utilizzati oggi. In breve, raggruppa tutti i moduli JavaScript (nonché 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 costituisce il nostro percorso iniziale
  • Un chunk secondario che contiene il nostro codice di ordinamento

Con l'utilizzo di importazioni dinamiche, un chunk secondario può essere caricato lentamente o caricato on demand. 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 nel 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 del processo TC39) per includere la funzionalità di importazione dinamica di un modulo. webpack ha già incluso il supporto per questa funzionalità e segue la stessa sintassi definita 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 promise è concatenata con un'altra .then che chiama un metodo sortInput per ordinare i tre valori di input. Alla fine della catena di promise, .catch() viene utilizzato per gestire i casi in cui la promise 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. Solo un piccolo bundle iniziale viene scaricato non appena l'app viene caricata.

Riquadro Rete che mostra un bundle JavaScript da 2,7 kB.

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

Riquadro Rete che mostra un bundle JavaScript da 2,7 kB seguito da un bundle JavaScript da 13,9 kB.

Nota come i numeri vengono comunque ordinati.

Conclusione

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

UI con caricamento lento

Quando esegui il caricamento lento di moduli di codice specifici, è importante considerare l'esperienza degli utenti con connessioni di rete più deboli. La suddivisione e il caricamento di un blocco di codice molto grande quando un utente invia un'azione possono 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 lento 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 di frequente. 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 lento rispetto all'utilizzo di importazioni dinamiche nel mezzo dell'applicazione.

Sebbene sia utile comprendere il funzionamento delle importazioni dinamiche, utilizza sempre il metodo consigliato dal tuo framework/dalla tua libreria per il caricamento lento di moduli specifici.

Precaricamento e precaricamento

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'utilizzo di commenti magici nelle istruzioni di importazione. Questo aspetto viene illustrato nel dettaglio nella guida Precarica i chunk critici.

Caricamento lento di più del codice

Le immagini possono costituire una parte significativa di un'applicazione. Il caricamento lento di quelli che si trovano below the fold o al di fuori dell'area visibile del dispositivo può velocizzare un sito web. Scopri di più su questo argomento nella guida di Lazysizes.