Minimizza e comprimi i payload di rete con gzip

Questo codelab illustra come minimizzare e comprimere il codice JavaScript bundle per la seguente applicazione migliora le prestazioni della pagina riducendo le dimensioni della richiesta da parte dell'app.

Screenshot dell'app

Misura

Prima di iniziare con l'aggiunta delle ottimizzazioni, è sempre consigliabile analizzare lo stato attuale dell'applicazione.

  • Per visualizzare l'anteprima del sito, premi Visualizza app. Quindi premi Schermo intero schermo intero.

Questa app, come descritto anche nella sezione "Rimuovere i contenuti inutilizzati codelab", ti permette di votare il tuo video preferito un gattino. 🐈

Ora dai un'occhiata alle dimensioni di questa applicazione:

  1. Premi "Ctrl+Maiusc+J" (o "Comando+Opzione+J" su Mac) per aprire DevTools.
  2. Fai clic sulla scheda Rete.
  3. Seleziona la casella di controllo Disabilita cache.
  4. Ricarica l'app.

Dimensioni del bundle originali nel riquadro Rete

Sebbene siano stati fatti molti progressi nella sezione "Rimuovere il codice inutilizzato" codelab per ridurre le dimensioni di questo bundle, i 225 kB sono comunque abbastanza grandi.

Minimizzazione

Considera il seguente blocco di codice.

function soNice() {
  let counter = 0;

  while (counter < 100) {
    console.log('nice');
    counter++;
  }
}

Se questa funzione viene salvata in un file autonomo, le dimensioni del file sono circa 112 B (byte).

Se vengono rimossi tutti gli spazi vuoti, il codice risultante avrà il seguente aspetto:

function soNice(){let counter=0;while(counter<100){console.log("nice");counter++;}}

Le dimensioni del file ora sarebbero di circa 83 B. Se viene ulteriormente danneggiata riducendo la lunghezza del nome della variabile e modificando alcune espressioni, il codice finale può finiranno in questo modo:

function soNice(){for(let i=0;i<100;)console.log("nice"),i++}

Le dimensioni del file raggiungono ora 62 B.

A ogni passaggio, la lettura del codice diventa più difficile. Tuttavia, l'interfaccia utente Il motore JavaScript li interpreta nello stesso modo. La offuscare il codice in questo modo può aiutare a ottenere file più piccoli dimensioni. 112 B non era molto all'inizio, ma c'era ancora il 50% riduzione delle dimensioni.

In questa applicazione, la versione 4 di webpack viene utilizzata come il bundler del modulo. La versione specifica può essere visualizzata in package.json.

"devDependencies": {
  //...
  "webpack": "^4.16.4",
  //...
}

La versione 4 minimizza già il bundle per impostazione predefinita durante la modalità di produzione. Utilizza TerserWebpackPlugin un plug-in per Terser. Terser è un noto strumento utilizzato per comprimere il codice JavaScript.

Per avere un'idea di come si presenta il codice minimizzato, procedi e fai clic su main.bundle.js mentre sei ancora nel riquadro Rete DevTools. Ora fai clic sul Scheda Risposta.

Risposta minimizzata

Il codice nella sua forma finale, minimizzato e manipolato, è mostrato nel corpo della risposta. Per scoprire le dimensioni del cofanetto se non fosse stato minimizzato, apri webpack.config.js e aggiorna la configurazione di mode.

module.exports = {
  mode: 'production',
  mode: 'none',
  //...

Ricarica l'applicazione e controlla di nuovo le dimensioni del bundle tramite Riquadro Rete DevTools

Dimensione del pacchetto da 767 kB

È una grossa differenza! 😅

Assicurati di annullare le modifiche qui prima di continuare.

module.exports = {
  mode: 'production',
  mode: 'none',
  //...

L'inclusione di una procedura per minimizzare il codice nell'applicazione dipende dagli strumenti che utilizzi:

  • Se viene utilizzato Webpack v4 o superiore, non è necessario svolgere alcun lavoro aggiuntivo poiché il codice viene minimizzato per impostazione predefinita in modalità di produzione. 👍
  • Se viene utilizzata una versione precedente di webpack, installa e includi TerserWebpackPlugin nel processo di compilazione del webpack. La documentazione lo spiega in dettaglio.
  • Esistono anche altri plug-in di minimizzazione che possono essere utilizzati, Ad esempio BabelMinifyWebpackPlugin e ClosureCompilerPlugin.
  • Se un bundler di moduli non viene utilizzato, usa Terser. come strumento di interfaccia a riga di comando o includerlo direttamente come dipendenza.

Compressione

Sebbene il termine "compressione" a volte è poco utilizzata per spiegare come viene ridotto durante il processo di minimizzazione, in realtà non viene compresso in senso letterale.

La compressione si riferisce in genere al codice che è stato modificato utilizzando un insieme di dati di compressione. A differenza della minimizzazione, che fornisce valido, il codice compresso deve essere decompresso prima di essere utilizzato.

Per ogni richiesta e risposta HTTP, i browser e i server web possono aggiungere intestazioni da includere e ulteriori informazioni sull'asset recuperato o ricevuto. Può essere visibile nella scheda Headers all'interno del riquadro Rete DevTools, dove si trovano sono visualizzati:

  • Generale rappresenta le intestazioni generali pertinenti all'intera richiesta-risposta un'interazione.
  • Intestazioni della risposta mostra un elenco di intestazioni specifiche per la risposta effettiva. dal server.
  • Intestazioni della richiesta mostra un elenco di intestazioni allegate alla richiesta dal di alto profilo.

Dai un'occhiata all'intestazione accept-encoding in Request Headers.

Accetta intestazione di codifica

accept-encoding viene utilizzato dal browser per specificare i contenuti formati di codifica o algoritmi di compressione. Esistono molti di compressione del testo, ma ce ne sono solo tre che supportata qui per la compressione (e decompressione) delle richieste di rete HTTP:

  • Gzip (gzip): la compressione più utilizzata per le interazioni server-client. Si basa sul Deflate ed è supportata in tutti i browser attuali.
  • Deflate (deflate): non comunemente utilizzata.
  • Brotli (br): una compressione più recente che mira a migliorare ulteriormente i rapporti di compressione, ottenendo caricamenti pagina ancora più rapidi. È supportata nel più recenti della maggior parte dei browser.

L'applicazione di esempio in questo tutorial è identica all'app completata nella Codelab su "Rimuovi il codice inutilizzato", tranne per il fatto che Ora Express viene utilizzato come framework del server. Nei prossimi alcune sezioni, la compressione statica e dinamica.

Compressione dinamica

La compressione dinamica comporta la compressione immediata degli asset quando questi vengono come richiesto dal browser.

Pro

  • Non è necessario creare e aggiornare le versioni compresse salvate degli asset fatto.
  • La compressione immediata funziona particolarmente bene per le pagine web che hanno generate in modo dinamico.

Contro

  • Compressione dei file a livelli più elevati per ottenere rapporti di compressione migliori richiede più tempo. Ciò può causare un hit da rendimento mentre l'utente attende che gli asset vengano vengono compressi prima di essere inviati dal server.

Compressione dinamica con Node/Express

Il file server.js è responsabile della configurazione del server Node che ospita per l'applicazione.

const express = require('express');

const app = express();

app.use(express.static('public'));

const listener = app.listen(process.env.PORT, function() {
  console.log('Your app is listening on port ' + listener.address().port);
});

Al momento, tutto ciò che devi fare è importare express e utilizzare express.static middleware per caricare tutti i file statici HTML, JS e CSS public/ (i file creati da webpack a ogni build).

Per assicurarti che tutti gli asset vengano compressi ogni volta che vengono richiesti, La libreria middleware compression . Inizia aggiungendolo come devDependency in package.json:

"devDependencies": {
  //...
  "compression": "^1.7.3"
},

E importalo nel file del server, server.js:

const express = require('express');
const compression = require('compression');

E aggiungilo come middleware prima del montaggio di express.static:

//...

const app = express();

app.use(compression());

app.use(express.static('public'));

//...

Ora ricarica l'app e controlla le dimensioni del bundle nel riquadro Rete.

Dimensioni del bundle con compressione dinamica

Da 225 KB a 61,6 KB! In Response Headers adesso, un content-encoding mostra che il server sta inviando questo file codificato con gzip.

Intestazione di codifica dei contenuti

Compressione statica

L'idea alla base della compressione statica è comprimere e salvare gli asset. in anticipo.

Pro

  • La latenza dovuta a livelli di compressione elevati non è più un problema. Non è necessario che avvenga nulla al volo per comprimere i file, poiché ora possono essere recuperati direttamente.

Contro

  • Gli asset devono essere compressi a ogni build. I tempi di compilazione possono aumentare molto se vengono utilizzati livelli di compressione elevati.

Compressione statica con Node/Express e webpack

Poiché la compressione statica implica la compressione anticipata dei file, puoi modificare le impostazioni in modo da comprimere gli asset come parte del passaggio di creazione. CompressionPlugin a questo scopo.

Inizia aggiungendolo come devDependency in package.json:

"devDependencies": {
  //...
  "compression-webpack-plugin": "^1.1.11"
},

Come per qualsiasi altro plug-in Webpack, importalo nel file di configurazione, webpack.config.js:

const path = require("path");

//...

const CompressionPlugin = require("compression-webpack-plugin");

e includilo nell'array plugins:

module.exports = {
  //...
  plugins: [
    //...
    new CompressionPlugin()
  ]
}

Per impostazione predefinita, il plug-in comprime i file di build utilizzando gzip. Dai un'occhiata nella documentazione per scoprire come aggiungere opzioni per utilizzare un algoritmo diverso o includere/escludere determinati file.

Quando l'app viene ricaricata e ricreata, viene generata una versione compressa del bundle principale ora creato. Apri la console Glitch per dare un'occhiata a cosa c'è all'interno la directory public/ finale gestita dal server Node.

  • Fai clic sul pulsante Strumenti.
  • Fai clic sul pulsante Console.
  • Nella console, esegui questi comandi per passare all'public e vedere tutti i suoi file:
cd public
ls

File finali di output nella directory pubblica

La versione compressa con gzip del bundle, main.bundle.js.gz, è ora salvata qui come beh. Per impostazione predefinita, CompressionPlugin comprime anche index.html.

La prossima cosa da fare è dire al server di inviare i file ogni volta che viene richiesta la versione JS originale. Questa operazione può essere eseguita definendo un nuovo percorso in server.js prima che i file vengano pubblicati con express.static.

const express = require('express');
const app = express();

app.get('*.js', (req, res, next) => {
  req.url = req.url + '.gz';
  res.set('Content-Encoding', 'gzip');
  next();
});

app.use(express.static('public'));

//...

app.get viene utilizzato per indicare al server come rispondere a una richiesta GET per un uno specifico endpoint. Viene quindi utilizzata una funzione di callback per definire come gestire richiesta. Il percorso funziona nel seguente modo:

  • Specificare '*.js' come primo argomento significa che questo funziona per ogni endpoint che viene attivato per recuperare un file JS.
  • Nel callback, .gz è allegato all'URL della richiesta e L'intestazione della risposta Content-Encoding è impostata su gzip.
  • Infine, next() assicura che la sequenza continui fino a qualsiasi callback che potrebbe essere il prossimo.

Una volta ricaricata l'app, dai un'altra occhiata al riquadro Network.

Riduzione delle dimensioni del bundle con la compressione statica

Come in precedenza, si è verificata una riduzione significativa delle dimensioni dei bundle.

Conclusione

Questo codelab ha trattato il processo di minimizzazione e compressione del codice sorgente. Entrambe queste tecniche stanno diventando predefinite in molti strumenti disponibile oggi stesso, quindi è importante scoprire se la tua toolchain è già li supporta o se devi iniziare ad applicare entrambi i processi personalmente.