Suddivisione del codice con importazioni dinamiche in Next.js

Come velocizzare l'app Next.js con la suddivisione del codice e le strategie di caricamento intelligenti.

Milica Mihajlija
Milica Mihajlija

Cosa imparerai?

Questo post illustra i diversi tipi di suddivisione del codice e come utilizzare le importazioni dinamiche per velocizzare le app Next.js.

Suddivisione del codice basata su route e componenti

Per impostazione predefinita, Next.js suddivide il codice JavaScript in blocchi separati per ogni route. Quando gli utenti caricano la tua applicazione, Next.js invia solo il codice necessario per la route iniziale. Quando gli utenti navigano nell'applicazione, recuperano i chunk associati agli altri percorsi. La suddivisione del codice in base ai route riduce al minimo la quantità di script che deve essere analizzata e compilata contemporaneamente, con tempi di caricamento delle pagine più rapidi.

Sebbene la suddivisione del codice in base alla route sia una buona impostazione predefinita, puoi ottimizzare ulteriormente il processo di caricamento con la suddivisione del codice a livello di componente. Se la tua app contiene componenti di grandi dimensioni, ti consigliamo di suddividerli in blocchi separati. In questo modo, tutti i componenti di grandi dimensioni che non sono fondamentali o che vengono visualizzati solo in determinate interazioni dell'utente (come i clic su un pulsante) possono essere caricati con il metodo lazy.

Next.js supporta import() dinamico, che consente di importare moduli JavaScript (inclusi i componenti React) in modo dinamico e di caricare ogni importazione come chunk separato. In questo modo puoi eseguire la suddivisione del codice a livello di componente e controllare il caricamento delle risorse in modo che gli utenti scarichino solo il codice necessario per la parte del sito che stanno visualizzando. In Next.js, questi componenti vengono generati lato server (SSR) per impostazione predefinita.

Importazioni dinamiche in azione

Questo post include diverse versioni di un'app di esempio costituita da una semplice pagina con un pulsante. Quando fai clic sul pulsante, puoi vedere un simpatico cucciolo. Man mano che scorri ogni versione dell'app, scoprirai in che modo le importazioni dinamiche sono diverse dalle importazioni statiche e come utilizzarle.

Nella prima versione dell'app, il cucciolo vive a components/Puppy.js. Per visualizzare il cucciolo sulla pagina, l'app importa il componente Puppy in index.js con un'istruzione di importazione statica:

import Puppy from "../components/Puppy";

Per verificare in che modo Next.js raggruppa l'app, controlla la traccia di rete in DevTools:

  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 la pagina.

Quando carichi la pagina, tutto il codice necessario, incluso il componente Puppy.js, viene raggruppato in index.js:

Scheda Rete di DevTools che mostra sei file JavaScript: index.js, app.js, webpack.js, main.js, 0.js e il file DLL (Dynamic Link Library).

Quando premi il pulsante Fai clic qui, alla scheda Rete viene aggiunta solo la richiesta per il file JPEG di uno cucciolo:

Scheda Rete di DevTools dopo il clic sul pulsante, che mostra gli stessi sei file JavaScript e un'immagine.

Lo svantaggio di questo approccio è che anche se gli utenti non fanno clic sul pulsante per vedere il cucciolo, devono caricare il componente Puppy perché è incluso in index.js. In questo piccolo esempio non è un problema, ma nelle applicazioni reali spesso è un enorme miglioramento caricare componenti di grandi dimensioni solo quando necessario.

Ora dai un'occhiata a una seconda versione dell'app, in cui l'importazione statica è sostituita da un'importazione dinamica. Next.js include next/dynamic, che consente di utilizzare le importazioni dinamiche per qualsiasi componente in Next:

import Puppy from "../components/Puppy";
import dynamic from "next/dynamic";

// ...

const Puppy = dynamic(import("../components/Puppy"));

Segui i passaggi del primo esempio per ispezionare la traccia di rete.

Al primo caricamento dell'app viene scaricato solo index.js. Questa volta è inferiore di 0,5 KB (da 37,9 KB a 37,4 KB) perché non include il codice per il componente Puppy:

La rete DevTools mostra gli stessi sei file JavaScript, tranne che il file index.js ora è 0,5 KB più piccolo.

Il componente Puppy ora si trova in un chunk separato, 1.js, che viene caricato solo quando premi il pulsante:

Scheda Rete di DevTools dopo il clic sul pulsante, che mostra il file 1.js aggiuntivo e l'immagine aggiunti alla fine dell'elenco dei file.

Nelle applicazioni reali, i componenti sono spesso molto più grandi e il loro caricamento lazy può ridurre il payload iniziale di JavaScript di centinaia di kilobyte.

Importazioni dinamiche con indicatore di caricamento personalizzato

Quando esegui il caricamento lento delle risorse, è buona norma fornire un indicatore di caricamento in caso di ritardi. In Next.js, puoi farlo fornendo un argomento aggiuntivo alla funzione dynamic():

const Puppy = dynamic(() => import("../components/Puppy"), {
  loading: () => <p>Loading...</p>
});

Per vedere l'indicatore di caricamento in azione, simula una connessione di rete lenta in DevTools:

  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. Nell'elenco a discesa Ritardo, seleziona 3G veloce.

  6. Premi il pulsante Fai clic qui.

Ora, quando fai clic sul pulsante, il componente impiega un po' di tempo a caricarsi e nel frattempo l'app visualizza il messaggio "Caricamento…".

Uno schermo scuro con il testo

Importazioni dinamiche senza SSR

Se devi eseguire il rendering di un componente solo lato client (ad esempio un widget chat), puoi farlo impostando l'opzione ssr su false:

const Puppy = dynamic(() => import("../components/Puppy"), {
  ssr: false,
});

Conclusione

Con il supporto delle importazioni dinamiche, Next.js offre la suddivisione del codice a livello di componente, che può ridurre al minimo i payload JavaScript e migliorare il tempo di caricamento dell'applicazione. Per impostazione predefinita, tutti i componenti vengono sottoposti a rendering lato server e puoi disattivare questa opzione quando necessario.