Suddivisione del codice con importazioni dinamiche in Next.js

Come velocizzare la tua app Next.js con strategie di suddivisione del codice e caricamento intelligente.

Milica Mihajlija
Milica Mihajlija

Data di pubblicazione: 8 novembre 2019

Scopri i diversi tipi di suddivisione del codice e come utilizzare le importazioni dinamiche per velocizzare le tue 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 l'applicazione, Next.js invia solo il codice necessario per la route iniziale. Quando gli utenti navigano nell'applicazione, recuperano i chunk associati alle altre route. La suddivisione del codice basata sulle route riduce al minimo la quantità di script che deve essere analizzata e compilata contemporaneamente, il che si traduce in tempi di caricamento della pagina più rapidi.

Sebbene la suddivisione del codice basata sulle 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, è consigliabile suddividerli in blocchi separati. In questo modo, tutti i componenti di grandi dimensioni che non sono critici o vengono visualizzati solo in determinate interazioni dell'utente (ad esempio, quando fa clic su un pulsante) possono essere caricati in modalità differita.

Next.js supporta l'importazione dinamicaimport(), che ti consente di importare dinamicamente moduli JavaScript (inclusi i componenti React) e caricare ogni importazione come un chunk separato. In questo modo, puoi dividere il 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 renderizzati 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, vedi un cucciolo carino. Man mano che avanzi nelle varie versioni dell'app, vedrai in che modo le importazioni dinamiche differiscono dalle importazioni statiche e come utilizzarle.

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

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

Per vedere come Next.js raggruppa l'app, esamina la traccia di rete in DevTools:

  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 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 (libreria di collegamento dinamico).

Quando premi il pulsante Fai clic qui, alla scheda Rete viene aggiunta solo la richiesta del JPEG del cucciolo:

Scheda Rete di DevTools dopo aver fatto 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 i componenti di grandi dimensioni solo quando necessario.

Ora dai un'occhiata a una seconda versione dell'app, in cui l'importazione statica viene sostituita da un'importazione dinamica. Next.js include next/dynamic, che consente di utilizzare 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 esaminare la traccia di rete.

Quando carichi l'app per la prima volta, viene scaricato solo index.js. Questa volta è 0,5 KB più piccolo (è passato da 37,9 KB a 37,4 KB) perché non include il codice per il componente Puppy:

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

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 aggiunta in fondo all'elenco dei file.

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

Importazioni dinamiche con indicatore di caricamento personalizzato

Quando carichi le risorse in modalità differita, è 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 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. Nell'elenco a discesa Limitazione, seleziona 3G veloce.

  6. Premi il pulsante Fai clic qui.

Ora, quando fai clic sul pulsante, il caricamento del componente richiede un po' di tempo e l'app mostra nel frattempo il messaggio "Caricamento…".

Una schermata scura con il testo

Importazioni dinamiche senza SSR

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

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

Conclusione

Grazie al 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 i tempi di caricamento dell'applicazione. Per impostazione predefinita, tutti i componenti vengono sottoposti a rendering lato server e puoi disattivare questa opzione ogni volta che è necessario.