Riduci i payload JavaScript con la suddivisione del codice

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, suddividere il 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 denominata Magic Sorter con tre campi per l'inserimento di numeri e un pulsante di ordinamento.

Misura

Come sempre, è importante misurare prima il rendimento di un sito web prima di tentare di aggiungere ottimizzazioni.

  1. Per visualizzare l'anteprima del sito, premi Visualizza app. Quindi premi A schermo intero schermo intero.
  2. Premi "Control+Maiusc+J" (o "Comando+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 della rete che mostra il bundle JavaScript di 71,2 KB.

71,2 KB di codice 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. Un errore comune è installare e importare intere dipendenze di terze parti di cui viene utilizzata solo una piccola parte.

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 avrebbero più senso per un'applicazione reale). Tuttavia, non vengono utilizzati in questo tutorial per motivi didattici 😈.

Entrambe le opzioni 3 e 4 contribuiscono a migliorare le prestazioni di questa applicazione. Le sezioni successive 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

Per importare solo il singolo metodo da lodash, è necessario modificare alcuni file. Per iniziare, sostituisci questa dipendenza in package.json:

"lodash": "^4.7.0",

con:

"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.

Riquadro della rete che mostra il bundle JavaScript di 15,2 KB.

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

Suddivisione del codice

webpack è uno dei più popolari compilatori di moduli open source in uso oggi. In breve, raggruppa tutti i moduli JavaScript (e anche 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 chunk distinti:

  • Uno responsabile del codice che compone il nostro percorso iniziale
  • Un chunk secondario contenente il codice di ordinamento

Con l'utilizzo delle importazioni dinamiche, un chunk secondario può essere caricato in modo lazy 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 nell'ascoltatore 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 in fase 3 del processo TC39) per includere la possibilità di importare dinamicamente un modulo. webpack ha già incluso il supporto per questa funzionalità e segue la stessa sintassi delineata dalla proposta.

import() restituisce una promessa e, al termine, viene fornito il modulo selezionato, che viene suddiviso in un chunk separato. Dopo che il modulo è stato restituito, module.default viene utilizzato per fare riferimento all'esportazione predefinita fornita da lodash. La promessa viene collegata 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 di nuovo il riquadro Rete. Non appena l'app viene caricata, viene scaricato solo un piccolo bundle iniziale.

Riquadro della rete che mostra il bundle JavaScript di 2,7 KB.

Dopo aver premuto il pulsante per ordinare i numeri inseriti, il chunk contenente il codice di ordinamento viene recuperato ed eseguito.

Pannello della rete che mostra un bundle JavaScript di 2,7 KB seguito da un bundle JavaScript di 13,9 KB.

Notare come i numeri vengano comunque ordinati.

Conclusione

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

Interfaccia utente con caricamento lento

Quando carichi in modo lazy moduli di codice specifici, è importante considerare come sarebbe l'esperienza per gli utenti con connessioni di rete più deboli. Se dividi e carica un blocco di codice molto grande quando un utente invia un'azione, l'applicazione potrebbe sembrare non funzionare, quindi ti consigliamo di mostrare un indicatore di caricamento di qualche tipo.

Caricamento lento dei moduli Node di terze parti

Non è sempre l'approccio migliore per il caricamento differito delle dipendenze di terze parti nella tua applicazione e dipende da dove le utilizzi. In genere, le dipendenze di terze parti sono suddivise in un bundle vendor separato che può essere memorizzato nella cache poiché non vengono aggiornate così di frequente. Scopri di più su come il plug-in SplitChunksPlugin può aiutarti a farlo.

Caricamento lento con un framework JavaScript

Molti framework e librerie popolari che utilizzano webpack forniscono astrazioni per facilitare il caricamento differito rispetto all'utilizzo delle importazioni dinamiche all'interno della applicazione.

Sebbene sia utile capire come funzionano le importazioni dinamiche, utilizza sempre il metodo consigliato dal tuo framework/dalla tua libreria per il caricamento differito di moduli specifici.

Precaricamento e pre-caricamento

Se possibile, sfrutta i suggerimenti del browser come <link rel="preload"> o <link rel="prefetch"> per provare a caricare i moduli critici ancora più in fretta. webpack supporta entrambi i suggerimenti tramite l'uso di commenti magici nelle affermazioni di importazione. Questo aspetto è spiegato in maggiore dettaglio nella guida sul precaricamento dei chunk critici.

Caricamento lento di più codice

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