Data di pubblicazione: 23 novembre 2024
Lo sviluppo basato su moduli offre alcuni vantaggi reali in termini di memorizzazione nella cache, aiutandoci a ridurre il numero di byte da inviare agli utenti. La granularità più fine del codice è utile anche per la storia di caricamento, in quanto ti consente di dare la priorità al codice critico nella tua applicazione.
Tuttavia, le dipendenze dei moduli introducono un problema di caricamento, in quanto il browser deve attendere il caricamento di un modulo prima di scoprire quali sono le sue dipendenze. Un modo per risolvere il problema è precaricare le dipendenze, in modo che il browser conosca in anticipo tutti i file e possa mantenere occupata la connessione.
<link rel="preload">
<link rel="preload">
è un modo per richiedere risorse in modo dichiarativo in anticipo,
prima che il browser ne abbia bisogno.
<head>
<link rel="preload" as="style" href="critical-styles.css">
<link rel="preload" as="font" crossorigin type="font/woff2" href="myfont.woff2">
</head>
Questo funziona particolarmente bene con risorse come i caratteri, che spesso sono nascosti all'interno dei file CSS, a volte a diversi livelli di profondità. In questa situazione, il browser dovrebbe attendere più round trip prima di scoprire che deve recuperare un file di caratteri di grandi dimensioni, quando avrebbe potuto utilizzare quel tempo per avviare il download e sfruttare la larghezza di banda completa della connessione.
<link rel="preload">
e il suo equivalente in intestazione HTTP forniscono un modo semplice e dichiarativo per comunicare immediatamente al browser i file critici necessari nell'ambito della navigazione corrente. Quando il browser rileva il pre-caricamento, avvia un download prioritario della risorsa, in modo che, quando sarà effettivamente necessaria, sia già stata recuperata o sia presente parzialmente. Tuttavia, non funziona per i moduli.
Perché <link rel="preload">
non funziona per i moduli?
È qui che le cose si complicano. Esistono diverse modalità di credenziali per le risorse e, per ottenere una corrispondenza nella cache, devono corrispondere, altrimenti finirai per recuperare la risorsa due volte. Inutile dire che il doppio recupero è negativo, perché spreca la larghezza di banda dell'utente e lo fa attendere più a lungo, senza un buon motivo.
Per i tag <script>
e <link>
, puoi impostare la modalità delle credenziali con l'attributo crossorigin
. Tuttavia, risulta che un <script type="module">
senza attributo
crossorigin
indica una modalità delle credenziali omit
, che non esiste
per <link rel="preload">
. Ciò significa che dovrai cambiare l'attributo crossorigin
sia in <script>
che in <link>
in uno degli altri valori e potresti non avere un modo semplice per farlo se ciò che stai tentando di precaricare è una dipendenza di altri moduli.
Inoltre, il recupero del file è solo il primo passaggio per l'esecuzione effettiva del codice.
Innanzitutto, il browser deve analizzarlo e compilarlo. Idealmente, questo dovrebbe avvenire anche in anticipo, in modo che quando il modulo è necessario, il codice sia pronto per essere eseguito. Tuttavia, V8 (il motore JavaScript di Chrome) analizza e compila i moduli diversamente da altri JavaScript. <link rel="preload">
non fornisce alcun modo per indicare che il file caricato è un modulo, quindi tutto ciò che il browser può fare è caricare il file e metterlo nella cache. Una volta caricato lo script utilizzando un
tag <script type="module">
(o se viene caricato da un altro modulo), il browser analizza
e compila il codice come modulo JavaScript.
Quindi <link rel="modulepreload">
è solo <link rel="preload">
per i moduli?
In breve, sì. Avendo un tipo link
specifico per il precaricamento dei moduli, possiamo scrivere HTML semplice senza preoccuparci della modalità di credenziali in uso. I valori predefiniti funzionano.
<head>
<link rel="modulepreload" href="super-critical-stuff.mjs">
</head>
[...]
<script type="module" src="super-critical-stuff.mjs">
Poiché ora il browser sa che stai precaricando un modulo, può essere intelligente e analizzare e compilare il modulo non appena è stato recuperato, anziché attendere fino a quando non tenta di eseguirlo.
Ma che dire delle dipendenze dei moduli?
Strano che tu lo chieda. In effetti, c'è un argomento che non è stato trattato in questo articolo: la ricorsione.
La specifica <link rel="modulepreload">
consente in realtà di caricare facoltativamente non solo il modulo richiesto, ma anche l'intero albero delle dipendenze. I browser non devono necessariamente farlo, ma possono.
Qual è quindi la soluzione cross-browser migliore per il precaricamento di un modulo e della relativa struttura ad albero delle dipendenze, dato che per eseguire l'app è necessaria la struttura completa delle dipendenze?
I browser che scelgono di precaricare le dipendenze in modo ricorsivo devono avere una deduplica solida delle dipendenze, quindi in generale la best practice consiste nel dichiarare il modulo e l'elenco piatto delle sue dipendenze e affidarsi al browser per non recuperare lo stesso modulo due volte.
<head>
<!-- dog.js imports dog-head.js, which in turn imports
dog-head-mouth.js, which imports dog-head-mouth-tongue.js. -->
<link rel="modulepreload" href="dog-head-mouth-tongue.mjs">
<link rel="modulepreload" href="dog-head-mouth.mjs">
<link rel="modulepreload" href="dog-head.mjs">
<link rel="modulepreload" href="dog.mjs">
</head>
Il precaricamento dei moduli migliora il rendimento?
Il precaricamento può contribuire a massimizzare l'utilizzo della larghezza di banda, indicando al browser cosa deve recuperare in modo che non rimanga inattivo durante questi lunghi viaggi di andata e ritorno. Se stai sperimentando con i moduli e riscontri problemi di prestazioni a causa di strutture ad albero di dipendenze profonde, la creazione di un elenco piatto di precaricamenti può essere di grande aiuto.
Detto questo, il rendimento del modulo è ancora in fase di sviluppo, quindi assicurati di esaminare attentamente cosa succede nella tua applicazione con gli Strumenti per gli sviluppatori e, nel frattempo, valuta la possibilità di raggruppare la tua applicazione in più blocchi. Tuttavia, in Chrome sono in corso molti lavori sui moduli, quindi stiamo per dare ai bundler il meritato riposo.