Riduci i payload JavaScript con la suddivisione del codice

La maggior parte delle pagine web e delle applicazioni sono composte da molte parti diverse. Invece di inviare tutto il codice JavaScript che costituisce 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 un'applicazione semplice che ordina tre numeri.

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

Misura

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

  1. Per visualizzare l'anteprima del sito, premi Visualizza app, quindi 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 Disabilita cache.
  5. Ricarica l'app.

Riquadro Network che mostra il bundle JavaScript da 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. L'installazione e l'importazione di intere dipendenze di terze parti dove viene utilizzata solo una piccola parte di queste è un errore comune.

Optimize

Esistono alcuni modi per tagliare le dimensioni del set:

  1. Scrivi 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 il metodo sortBy solo da lodash e non dall'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 (probabilmente sarebbero più adatti a un'applicazione reale). Tuttavia, non sono utilizzati in questo tutorial ai fini dell'insegnamento 👻.

Entrambe le opzioni 3 e 4 consentono di migliorare le prestazioni di questa applicazione. Nelle prossime sezioni di questo codelab verranno trattati questi passaggi. Come per qualsiasi tutorial di programmazione, prova sempre a scrivere il codice autonomamente anziché copiare e incollare il codice.

Importa solo ciò che ti serve

È necessario modificare alcuni file 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 vengono ordinati i 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 controlla di nuovo il riquadro Rete.

Riquadro Network che mostra il bundle JavaScript da 15,2 kB.

Per questa applicazione, le dimensioni del bundle sono state ridotte di oltre 4 volte con pochissimo lavoro, ma c'è ancora più margine di miglioramento.

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 costituiscono 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 blocco secondario contenente il nostro codice di ordinamento

Con l'utilizzo delle importazioni dinamiche, è possibile caricare un blocco secondario tramite caricamento lento o on demand. In questa applicazione, il codice che compone il blocco 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";

Importa poi all'interno del listener di eventi che si attiva quando premi 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) che include la funzionalità di importazione dinamica di un modulo. webpack ha già incluso il supporto a 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. Una volta restituito il modulo, module.default viene utilizzato per fare riferimento all'esportazione predefinita fornita da lodash. La promessa è concatenata a un altro .then che chiama un metodo sortInput per ordinare i tre valori di input. Alla fine della catena delle 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 interpreta 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 di nuovo sotto controllo il riquadro Rete. Non appena viene caricata l'app, viene scaricato solo un bundle iniziale.

Riquadro Network che mostra il bundle JavaScript da 2,7 kB.

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

Riquadro di rete che mostra il bundle JavaScript da 2,7 kB seguito da un bundle JavaScript da 13,9 kB.

Come puoi vedere, i numeri vengono 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 e, di conseguenza, portare direttamente a tempi di caricamento delle pagine molto più rapidi. Tuttavia, ci sono alcuni aspetti importanti da considerare prima di includere questa ottimizzazione nell'applicazione.

Interfaccia utente con caricamento lento

Durante il caricamento lento di moduli di codice specifici, è importante considerare come sarebbe l'esperienza per gli 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 può far sembrare che l'applicazione abbia smesso di funzionare, quindi considera la possibilità di mostrare un indicatore di caricamento di qualche tipo.

Caricamento lento dei moduli dei nodi di terze parti

Non è sempre l'approccio migliore alle dipendenze di terze parti con caricamento lento nell'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é si aggiornano con frequenza minore. Leggi ulteriori informazioni su come lo SplitChunksPlugin può aiutarti a farlo.

Caricamento lento con un framework JavaScript

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

Sebbene sia utile per capire come funzionano le importazioni dinamiche, usa sempre il metodo consigliato dal tuo framework o dalla tua libreria per eseguire 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 moduli critici ancora prima. Il webpack supporta entrambi i suggerimenti tramite l'utilizzo di commenti magici nelle istruzioni di importazione. Questa procedura è descritta in maggiore dettaglio nella guida Precarica i blocchi critici.

Caricamento lento oltre il codice

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