We want to hear from you!Take our 2020 Community Survey!

Code-Splitting

Impacchettamento

Molte applicazioni React hanno i loro file “impacchettati” usando strumenti come Webpack, Rollup oppure Browserify. Il processo di “impacchettamento” avviene prendendo tutti i file importati e unendoli tutti in un unico file, chiamato “bundle”. Questo file può essere poi incluso all’interno della pagina web per caricare l’intera applicazione tutta in una volta.

Esempio

App:

// app.js
import { add } from './math.js';

console.log(add(16, 26)); // 42
// math.js
export function add(a, b) {
  return a + b;
}

Bundle:

function add(a, b) {
  return a + b;
}

console.log(add(16, 26)); // 42

Nota:

I tuoi pacchetti avranno un aspetto molto diverso da questo.

Se state usando Create React App, Next.js, Gatsby, o qualche tool simile, potreste avere una configurazione di Webpack che effettua il processo d’impacchettamento della tua applicazione.

In caso contrario è necessario impostare l’impacchettamento dell’applicazione manualmente. Ad esempio puoi seguire queste guide sulla documentazione di Webpack, Installation e Getting Started.

Code Splitting

Il processo d’impacchettamento va bene, ma se l’applicazione cresce allora, di conseguenza, pure il bundle cresce, e questo specialmente se si includono librerie di terze parti. E’ necessario prestare attenzione al codice che si include all’interno del proprio bundle, in modo tale da non renderlo troppo pesante per non causare rallentamenti nella sua esecuzione.

Per evitare di avere un bundle enorme, è buona pratica iniziare a suddividere il proprio bundle. Il Code-Splitting (letteralmente “spezzamento del codice”) è una funzionalità supportata da Webpack, Rollup e Browserify (attraverso factor-bundle) i quali creano molteplici bundle che possono essere caricati dinamicamente a tempo di esecuzione.

Spezzare il codice della propria applicazione può aiutare ad effettuare il “lazy-load (caricamento pigro)” di funzionalità che sono necessarie in quel preciso istante, e questo processo può incrementare di parecchio le performance della propria applicazione. Anche se non è stato ridotto la quantità complessiva di codice dell’applicazione, abbiamo evitato di caricare codice di cui l’utente potrebbe non avere mai bisogno ed è stata ridotta la quantità di codice necessaria durante il caricamento iniziale.

import()

Il miglior modo per introdurre il code splitting all’interno dell’applicazione è attraverso la sintassi import().

Prima:

import { add } from './math';

console.log(add(16, 26));

Dopo:

import("./math").then(math => {
  console.log(math.add(16, 26));
});

Quando Webpack incontra questa sintassi, inizia automaticamente il code splitting dell’applicazione. Se state utilizzando Create React App, questo è già automaticamente configurato per te e tu puoi iniziare ad utilizzarlo immediatamente. E’ anche supportato da Next.js.

Se state configurando Webpack autonomamente, probabilmente dovrai leggere la guida sul “code splitting” di Webpack. Il tuo webpack dovrebbe assomigliare a questo.

Quando usate Babel dovete assicurarvi che esso possa effettuare il parsing degli import dinamici. Per fare questo avete bisogno di @babel/plugin-syntax-dynamic-import.

React.lazy

Nota:

React.lazy and Suspense are not yet available for server-side rendering. If you want to do code-splitting in a server rendered app, we recommend Loadable Components. It has a nice guide for bundle splitting with server-side rendering.

La funzione React.lazy ti permette di effettuare un import dinamico come se fosse un normale componente.

Prima:

import OtherComponent from './OtherComponent';

Dopo:

const OtherComponent = React.lazy(() => import('./OtherComponent'));

L’istruzione sopra carica il pezzo di codice contenente il componente OtherComponent quando viene renderizzato per la prima volta.

La funzione React.lazy prende in ingresso una funzione che, dinamicamente, chiama il metodo import(). Quello che viene restituito è una Promise che si risolve in un modulo contente l’export di default del componente React.

Il componente “pigro” viene poi renderizzato all’interno di un componente Suspense il quale ci permette di mostrare dei contenuti di fallback (come ad esempio degli indicatori di caricamente) mentre stiamo aspettando che il componente sia completamente caricato.

import React, { Suspense } from 'react';

const OtherComponent = React.lazy(() => import('./OtherComponent'));

function MyComponent() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <OtherComponent />
      </Suspense>
    </div>
  );
}

La prop fallback accetta un qualsiasi elemento React che si vuole renderizzare nel mentre stiamo aspettando che il componente sia caricato. E’ possibile mettere il componente Suspense ovunque sopra il componente da caricare in modo lazy. E’ anche possibile circondare il componente da caricare in modo lazy col componente Suspense.

import React, { Suspense } from 'react';

const OtherComponent = React.lazy(() => import('./OtherComponent'));
const AnotherComponent = React.lazy(() => import('./AnotherComponent'));

function MyComponent() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <section>
          <OtherComponent />
          <AnotherComponent />
        </section>
      </Suspense>
    </div>
  );
}

Contenitori di Errori

Se altri moduli falliscono nel caricamente (ad esempio a causa di problemi di rete), verrà sollevato un errore. Puoi gestire questi errori per mostrare un Contenitore di Errori. Una volta che è stato creato il proprio contenitore di errori, è possibile utilizzarlo ovunque sopra i componenti lazy per mostrare uno stato di errore quando ci sono errori di rete.

import React, { Suspense } from 'react';
import MyErrorBoundary from './MyErrorBoundary';

const OtherComponent = React.lazy(() => import('./OtherComponent'));
const AnotherComponent = React.lazy(() => import('./AnotherComponent'));

const MyComponent = () => (
  <div>
    <MyErrorBoundary>
      <Suspense fallback={<div>Loading...</div>}>
        <section>
          <OtherComponent />
          <AnotherComponent />
        </section>
      </Suspense>
    </MyErrorBoundary>
  </div>
);

Code splitting basato su rotte

Decidere dove, nella propria app, introdurre il code splitting può essere complicato. Assicurati di scegliere posti che divideranno i pacchetti in modo uniforme, senza diminuire l’esperienza dell’utente.

Un buon posto per iniziare sono le rotte. La maggior parte delle persone sul Web è abituata a caricare le transizioni di pagina che richiedono un po ‘di tempo. Tendi anche a rieseguire il rendering dell’intera pagina contemporaneamente, quindi è improbabile che i tuoi utenti interagiscano contemporaneamente con altri elementi della pagina.

Qui di seguito possiamo vedere un esempio code splitting, basato sulle rotte, utilizzando libreria come React Router con React.lazy.

import React, { Suspense, lazy } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';

const Home = lazy(() => import('./routes/Home'));
const About = lazy(() => import('./routes/About'));

const App = () => (
  <Router>
    <Suspense fallback={<div>Loading...</div>}>
      <Switch>
        <Route exact path="/" component={Home}/>
        <Route path="/about" component={About}/>
      </Switch>
    </Suspense>
  </Router>
);

Named Exports

Ad oggi React.lazy supporta solamente gli export di default. Se il modulo che vogliamo importare utilizza export nominali, possiamo creare un modulo intermedio che lo re-esporta come default. In questo modo ci assicuriamo che il tree shaking continui a funzionare e che non vengano caricati componenti non utilizzati.

// ManyComponents.js
export const MyComponent = /* ... */;
export const MyUnusedComponent = /* ... */;
// MyComponent.js
export { MyComponent as default } from "./ManyComponents.js";
// MyApp.js
import React, { lazy } from 'react';
const MyComponent = lazy(() => import("./MyComponent.js"));
Is this page useful?Edit this page