Nella natura dinamica del moderno JavaScript, è essenziale ricordare che “vecchio” non significa necessariamente “superato” e “nuovo” non implica sempre “migliore”.

La chiave per scegliere la tecnologia giusta sta nel suo allineamento con le esigenze del proprio progetto. Questo principio risuona fortemente quando si considerano i bundler di moduli JavaScript. Che si tratti di un bundler che ha superato la prova del tempo o di uno appena introdotto, ognuno di essi presenta vantaggi e limiti distinti.

Questo articolo analizza due strumenti importanti e popolari: Vite e Webpack. Valutiamo questi bundler in base alle loro caratteristiche, alle loro distinzioni, alle loro filosofie architettoniche e al modo in cui si integrano nell’ecosistema degli sviluppatori.

Cos’è un bundler di moduli JavaScript?

Più asset che passano attraverso un filtro
Javascript Bundling

Un bundler JavaScript è uno strumento utilizzato nello sviluppo web per combinare più file JavaScript in un unico file, noto come bundle. Semplifica la gestione del codice JavaScript riducendo il numero di richieste che l’applicazione web deve effettuare, migliorando così le prestazioni.

Ad esempio, prendiamo in esame due file JavaScript separati: module1.js e module2.js. module1.js contiene:

// module1.js
export const greet = (name) => {
    console.log(`Hello, ${name}!`);
}

E modulo2.js contiene:

// module2.js
export const farewell = (name) => {
    console.log(`Goodbye, ${name}!`);
}

Per raggruppare questi moduli in un unico file, possiamo utilizzare un bundler come Rollup, Webpack o Parcel. Ad esempio, se dovessimo creare un file index.js all’interno della cartella del progetto con il codice seguente:

// index.js
import { greet } from './module1.js';
import { farewell } from './module2.js';

greet('Kinsta');
farewell('Server Troubles');

L’utilizzo di un bundler JavaScript combina i moduli module1.js, module2.js e index.js in un unico bundle ottimizzato per l’utilizzo di un’applicazione web.

Mentre i browser moderni supportano i moduli ES e tecnologie come HTTP/2, che risolvono i problemi di overhead delle richieste, i bundler JavaScript rimangono indispensabili per una serie di miglioramenti del codice. Eseguono trasformazioni essenziali del codice, tra cui minificazione, transpiling e ottimizzazione.

Inoltre, i bundler di moduli JavaScript garantiscono la compatibilità tra i vari browser. Aiutano a risolvere i problemi specifici dei browser e assicurano un’esperienza coerente agli utenti, indipendentemente dal browser web scelto.

Questo processo di bundling non solo accelera la velocità di caricamento di un’applicazione web, ma garantisce anche prestazioni efficienti, soprattutto negli ambienti di produzione. Ora che abbiamo presentato i bundler JavaScript e il loro ruolo nello sviluppo web, spostiamo la nostra attenzione su Vite e Webpack.

Vite e Webpack: introduzione e panoramica

È chiaro che Vite e Webpack sono leader nel settore in rapida crescita dello sviluppo web moderno, dove la gestione delle risorse e l’ottimizzazione dei bundle sono fondamentali. Ma prima di addentrarci in un confronto dettagliato, diamo una rapida occhiata a questi bundler e capiamo cosa li distingue.

Vite: sviluppo rapido e on-demand

Vite, che si pronuncia “vit”, è una soluzione che cambia le carte in tavola per gli sviluppatori web, dando priorità alla velocità e all’efficienza. Ciò che distingue Vite è il suo approccio al bundling on-demand. Invece di preconfezionare tutto il codice e le risorse, Vite sfrutta i moduli ES nativi dei browser moderni, fornendo il codice direttamente al browser durante lo sviluppo. Questo porta a un Hot Module Replacement (HMR) quasi istantaneo e a tempi di avvio ridotti.

Il server di sviluppo di Vite brilla per questo approccio on-demand, che consente agli sviluppatori di vedere rapidamente le modifiche senza doverle ricompilare completamente. Utilizza anche il Rollup, per una compilazione efficiente della produzione. Di conseguenza, Vite offre uno sviluppo rapidissimo e solide prestazioni di produzione.

Webpack: organizzato e adattabile

Webpack è la pietra miliare dello sviluppo web moderno, in costante evoluzione dal 2012. Il punto di forza di Webpack è il modo in cui organizza i componenti del sito web. Ottimizza i tempi di caricamento e l’esperienza dell’utente organizzando il codice in moduli.

L’adattabilità di Webpack è un vantaggio notevole. Gli sviluppatori possono personalizzare i progetti per attività semplici o complesse. Gli sviluppatori possono personalizzare i flussi di lavoro e costruire i processi con precisione.

Somiglianze e differenze tra Vite e Webpack

Ora che abbiamo discusso dei concetti di base di Vite e Webpack, esploriamo le loro somiglianze e differenze in modo più dettagliato. Nell’analizzare questi bundler, esamineremo vari aspetti per ottenere una panoramica completa di come si confrontano e dove eccellono.

1. Architettura e filosofia

Entrambi i bundler offrono prospettive uniche sulla costruzione e sull’ottimizzazione delle applicazioni web. Hanno in comune l’approccio ai plugin, che consente alla comunità di creare ulteriori plugin vantaggiosi che estendono le loro funzionalità, rendendoli strumenti versatili per gli sviluppatori.

La filosofia di base di Vite ruota attorno alla leggerezza e all’estensibilità. Aderisce a una strategia minimalista, concentrandosi sui modelli di sviluppo di applicazioni web più comuni. Questo approccio garantisce la manutenibilità del progetto a lungo termine.

L’affidamento di Vite a un sistema di plugin basato su rollup evita l’ingrossamento del core consentendo l’implementazione di funzionalità attraverso plugin esterni. Questo favorisce un nucleo snello e incoraggia un ecosistema fiorente di plugin ben mantenuti. Inoltre, Vite collabora attivamente con il progetto Rollup per mantenere la compatibilità e un ecosistema di plugin condiviso.

Webpack offre agli sviluppatori la possibilità di personalizzazione, consentendo loro di adattare i progetti a esigenze specifiche, dalle attività di base alle imprese più complesse. Offre flessibilità nella configurazione di ogni aspetto del processo di creazione, il che lo rende una scelta obbligata per chi cerca un’esperienza di sviluppo personalizzata.

Inoltre, Webpack introduce l’approccio modulare, simile all’assemblaggio dei blocchi Lego per i progetti web. Tutto ciò che è presente nella base di codice è un modulo per Webpack, che può esprimere le sue dipendenze in molti modi. Alcuni esempi sono:

  1. Dichiarazione ES2015 import.
  2. Dichiarazione CommonJS require().
  3. Dichiarazione AMD define e require
  4. @import all’interno di un file css/sass/less.
  5. URL di un’immagine in un foglio di stile url() o in un file HTML <img src="">.

La filosofia di Vite in azione

La filosofia architettonica di Vite di essere snella ed estensibile è evidente nel suo approccio alla costruzione di applicazioni web. Supponiamo di stare sviluppando un’applicazione web e di voler includere le moderne funzionalità di JavaScript come i moduli ES. Con Vite possiamo farlo senza alcuno sforzo. Ecco un esempio semplificato:

// app.js
import { greet } from './utilities.js';

const worker = new Worker(new URL('./worker.js', import.meta.url));

// Simulate a calculation in the web worker
worker.postMessage({ input: 42 });

worker.onmessage = (e) => {
  const result = e.data.result;
  console.log(`Result from the web worker: ${result}`);
};

const message = greet('Hello, Vite!');
console.log(message);

In questo frammento di codice, Vite accetta l’uso dei moduli ES e raggruppa il codice al volo, evitando le lunghe fasi di raggruppamento durante lo sviluppo. Questo approccio modulare permette di gestire le dipendenze in modo efficiente, creando una base di codice manutenibile. Questo dimostra l’impegno di Vite per il minimalismo e le esperienze a misura di sviluppatore.

La filosofia di Webpack in azione

La filosofia modulare di Webpack è particolarmente vantaggiosa quando si lavora su progetti di grandi dimensioni. Immaginiamo di dover costruire un’applicazione web di grandi dimensioni con diversi moduli JavaScript. Con Webpack, possiamo assemblare questi moduli senza problemi, migliorando la leggibilità, la manutenibilità e il tempo di caricamento del sito web. Ecco un esempio semplificato:

// webpack.config.js
const path = require('path');

module.exports = {
  entry: './app.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    rules: [
      {
        test: /.js$/,
        use: 'babel-loader',
        exclude: /node_modules/,
      },
    ],
  },
};

In questo esempio, Webpack permette di configurare il processo di creazione, ottimizzare il codice e gestire le risorse in modo efficiente. Organizzando il progetto in moduli e utilizzando caricatori come Babel, possiamo scrivere codice pulito e modulare che migliora l’esperienza dell’utente. Questo dimostra l’impegno di Webpack nel fornire personalizzazione e flessibilità, garantendo agli sviluppatori la possibilità di adattare i loro progetti a esigenze specifiche.

Sebbene Vite e Webpack abbiano filosofie architettoniche distinte, hanno in comune l’impegno a superare i confini del moderno sviluppo web. Vite si concentra su modelli di codifica moderni, promuovendo i moduli ECMAScript (ESM) per il codice sorgente e incoraggiando standard moderni come la nuova sintassi Worker per i web worker.

Webpack, invece, si è evoluto come risposta alle sfide presentate da Node.js e CommonJS, favorendo l’adozione dei moduli nello sviluppo web. La raccolta automatica delle dipendenze di Webpack, unita ai miglioramenti delle prestazioni, garantisce un’esperienza di sviluppo senza soluzione di continuità.

2. Popolarità, comunità ed ecosistema

Vite e Webpack hanno tempistiche diverse che ne determinano la popolarità e la comunità.

Un confronto di Google Trends tra Vite e Webpack negli ultimi 5 anni
Vite e Webpack a confronto su Google Trends negli ultimi 5 anni.

Vite è un nuovo arrivato, che ha fatto il suo debutto nel 2020. Nonostante la sua esistenza relativamente breve, Vite ha rapidamente guadagnato attenzione, diventando un attore promettente nel campo dello sviluppo web moderno.

Al contrario, Webpack ha un notevole vantaggio, essendo stato fondato nel 2012. Il tempo trascorso nel settore gli ha permesso di sviluppare un ecosistema maturo e una solida comunità.

npmtrends comparison for Vite and Webpack in the last 5 years.
Vite e Webpack a confronto su npmtrends negli ultimi 5 anni.

Il grafico qui sopra di npmtrends illustra il confronto del numero di download tra Vite e Webpack. Mostra chiaramente che Webpack mantiene costantemente una posizione di rilievo in termini di numero di download, sottolineando la sua presenza di lunga data e l’ampiezza del suo utilizzo all’interno della comunità degli sviluppatori.

Vite e Webpack a confronto su star-history.
Vite e Webpack a confronto su star-history.

Se analizziamo le stelle di GitHub utilizzando la star-history, che è una misura della popolarità e del supporto della comunità, scopriamo che Vite vanta ben 60.318 stelle, mentre Webpack mantiene una forte presenza con 63.598 stelle. Il numero di stelle riflette il riconoscimento e l’impegno attivo di entrambi i progetti. La rapida crescita di Vite e la popolarità sostenuta di Webpack li rendono risorse preziose nel panorama dello sviluppo web.

3. Configurazione e facilità d’uso

Sia Vite che Webpack offrono numerose opzioni di configurazione per adattare il bundle alle esigenze specifiche di un developer. Tuttavia, ci sono differenze significative che meritano la nostra attenzione. Analizziamo la configurazione e la facilità d’uso di entrambi gli strumenti.

La configurazione semplificata di Vite

Vite si distingue per la sua filosofia zero-config, pensata per semplificare il percorso di sviluppo web. Ciò significa che possiamo creare una libreria di componenti Vue 3 di base con il minimo sforzo. Ecco una semplice configurazione di Vite per un progetto di questo tipo:

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()],
})

Nell’esempio precedente, abbiamo importato e installato solo il plugin ufficiale di Vite per Vue.js. La magia di Vite sta nella sua capacità di rilevare automaticamente le impostazioni giuste per la maggior parte dei progetti.

Complessità di configurazione di Webpack

Webpack, invece, tende a richiedere una configurazione più dettagliata. Anche se nelle ultime versioni si è orientato verso un approccio zero-config, non è così automatico come Vite. Per Vue 3, una configurazione di base di Webpack potrebbe assomigliare a questa:

const webpack = require('webpack');
const path = require('path');
const { HotModuleReplacementPlugin } = require('webpack');
const { VueLoaderPlugin } = require('vue-loader');

module.exports = {
    entry: './src/main.js',
    output: {
        path: path.resolve(__dirname, './build'),
        filename: 'bundle.js',
    },
    module: {
        rules: [
            {
                test: /.js$/,
                exclude: /(node_modules|bower_components)/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env'],
                    },
                },
            },
            {
                test: /.vue$/,
                use: {
                    loader: 'vue-loader',
                },
            },
            {
                test: /.css$/,
                use: ['vue-style-loader', 'css-loader'],
            },
        ],
    },
    resolve: {
        alias: {
            vue: 'vue/dist/vue.js',
        },
    },
    plugins: [
    new HotModuleReplacementPlugin(),
    new VueLoaderPlugin(),
    ]
};

Rispetto a Vite, la configurazione di Webpack comporta un’impostazione più manuale. Le complessità includono la specificazione dei percorsi di ingresso e di uscita, la configurazione dei caricatori per i diversi tipi di file e l’impostazione di plugin per funzionalità specifiche. Vediamo di suddividere ogni parte della configurazione e di evidenziarne le complessità:

  • Entry e output: entry specifica il punto di ingresso dell’applicazione, dove Webpack inizierà il bundle. In questo caso, è impostato su ./src/main.js, supponendo che il file JavaScript principale dell’applicazione si trovi nella directory src, mentre output definisce dove devono essere salvati i file in bundle. Il percorso di uscita viene risolto utilizzando path.resolve e il file bundle risultante viene chiamato bundle.js e salvato nella directory di build.
  • Module Rules: la sezione module.rules definisce come vengono elaborati i diversi tipi di file. In questo caso, ci sono regole per i file JavaScript (babel-loader per la transpilazione), per i componenti Vue a file singolo (vue-loader) e per i file CSS (vue-style-loader e css-loader per la gestione degli stili).
  • Configurazione degli alias: la sezione resolve.alias definisce gli alias per le importazioni dei moduli. In questo caso, si tratta di configurare un alias per Vue a vue/dist/vue.js.
  • Plugin: la sezione dei plugin include HotModuleReplacementPlugin che abilita l’hot module replacement, una funzione che permette di vedere le modifiche senza ricaricare l’intera pagina durante lo sviluppo, mentreVueLoaderPlugin è necessaria per l’elaborazione dei componenti Vue a file singolo.

Per concludere questa sezione, Vite si distingue per la facilità d’uso, offrendo una configurazione semplificata e un’esperienza di sviluppo snella. I requisiti minimi di configurazione e l’uso di moduli ES nativi lo rendono ideale per i principianti e per lo sviluppo rapido.

Al contrario, l’ampia configurabilità di Webpack, pur essendo vantaggiosa per progetti complessi, può rappresentare una sfida per gli sviluppatori alle prime armi. L’intricata configurazione e manutenzione può rallentare lo sviluppo, soprattutto per i progetti più piccoli.

4. Server di sviluppo

Il server di sviluppo gioca un ruolo fondamentale nel flusso di lavoro di uno sviluppatore, influenzando l’efficienza e la produttività. Mettiamo a confronto Vite e Webpack, valutando le prestazioni e l’usabilità del loro server di sviluppo per trovare lo strumento migliore per il nostro progetto di sviluppo web.

Configurazione del server

Vite si distingue per il suo server di sviluppo integrato e pronto all’uso, che spesso elimina la necessità di una configurazione approfondita.

Al contrario, Webpack offre flessibilità ma richiede una configurazione aggiuntiva. Gli sviluppatori possono scegliere opzioni come la modalità di osservazione di Webpack, webpack-dev-server e webpack-dev-middleware per la compilazione automatica del codice in caso di modifiche. Tuttavia, in genere è necessaria una configurazione per stabilire e mettere a punto queste opzioni.

Velocità del Cold Start

Le configurazioni tradizionali basate su bundler comportano un crawling avido e richiedono la creazione dell’intera applicazione prima di servirla, con conseguenti ritardi evidenti, soprattutto nei progetti complessi.

Vite rivoluziona il cold start con un approccio radicalmente diverso, riducendo drasticamente i tempi di inizializzazione:

Screenshot della velocità di bundling di esbuild per il progetto three.js rispetto ad altri bundler
Tempo di creazione di Esbuild per creare un bundle di produzione di 10 copie della libreria three.js da zero utilizzando le impostazioni predefinite. (Fonte immagine: Esbuild)
  • Gestione efficiente delle dipendenze: Vite sfrutta esbuild, un bundler ad alte prestazioni basato su Go, per il pre-bundle delle dipendenze, tra cui JavaScript semplice e moduli di grandi dimensioni. Come parte del processo di pre-bundling, Vite ottimizza le prestazioni unendo le dipendenze ESM con numerosi moduli interni in un unico modulo: ad esempio, lodash-es contiene oltre 600 moduli interni. Quando si utilizzano i metodi tradizionali e si importa una funzione come debounce, si attivano oltre 600 richieste HTTP. La soluzione di Vite consiste nel raggruppare lodash-es in un unico modulo, riducendo le richieste HTTP a una sola. Questa drastica riduzione delle richieste aumenta in modo significativo la velocità di caricamento delle pagine sul server di sviluppo.

    Grafico del server di sviluppo basato su ESM
    ESM. (Fonte immagine: Vite)

  • Caricamento del codice sorgente su richiesta: Vite utilizza moduli ES nativi per servire il codice sorgente, riducendo al minimo il carico e la latenza del server. La trasformazione e il caricamento del codice sorgente avvengono su richiesta del browser, migliorando l’efficienza e riducendo i tempi di attesa.

    Grafico del server di sviluppo basato su bundle
    Bundle. (Fonte immagine: Vite)

Webpack, invece, adotta un approccio basato su bundle, pre-bundling del codice sorgente e delle dipendenze, allungando i tempi di avvio del server durante lo sviluppo. Rispetto all’efficiente inizializzazione di Vite, il tempo di configurazione del server di Webpack è intrinsecamente più lungo.

Tuttavia, l’approccio di caricamento on-demand di Vite può introdurre un leggero ritardo quando gli utenti navigano verso percorsi che richiedono dati, CSS e risorse aggiuntive. Questo è particolarmente evidente se queste risorse richiedono ulteriori passaggi di impacchettamento. Al contrario, la strategia di Webpack assicura che tutti i dati del sito siano disponibili, rendendo più veloce la navigazione del browser verso le nuove pagine del server di sviluppo.

HMR (Hot Module Replacement)

Vite utilizza l’HMR rispetto all’ESM nativo, riducendo il carico del server e la latenza grazie allo scarico di alcune operazioni di bundling al browser. Questo garantisce aggiornamenti rapidi senza ricaricare l’intera pagina, cosa fondamentale per avere un feedback in tempo reale durante lo sviluppo.

Anche Webpack supporta HMR, consentendo aggiornamenti in tempo reale e preservando lo stato dell’applicazione durante lo sviluppo. Tuttavia, le potenziali limitazioni nell’utilizzo dei moduli ES nativi possono comportare un maggiore carico e latenza del server.

Prestazioni della cache

Il caching è essenziale per migliorare le prestazioni delle applicazioni web, riducendo il carico e i tempi di build grazie al riutilizzo delle risorse memorizzate.

La cache in Vite è gestita da una cache del file system che aggiorna le dipendenze in base alle modifiche apportate a package.json, lockfiles e vite.config.js. Ottimizza i ricaricamenti delle pagine mettendo in cache le richieste di dipendenza risolte.

Anche Webpack utilizza la cache del file system, cancellando i file modificati in modalità watch e svuotando la cache prima di ogni compilazione in modalità non-watch, ma richiede una configurazione personalizzata per una cache ottimale.

Per concludere il confronto tra i server di sviluppo, Vite e Webpack offrono approcci diversi ai server di sviluppo:

  • Vite fornisce un server di sviluppo pronto all’uso, riducendo al minimo i costi di configurazione.
  • Webpack offre flessibilità di configurazione, ma richiede un’impostazione aggiuntiva.
  • Vite eccelle nella velocità di cold start e nell’HMR per le modifiche rapide al codice.
  • Webpack ha prestazioni migliori per quanto riguarda la velocità di navigazione del browser grazie ai dati del sito preconfezionati.
  • Entrambi supportano l’HMR ma hanno meccanismi diversi per la gestione dei moduli.
  • Vite gestisce la cache locale e del browser senza problemi, mentre Webpack richiede una configurazione personalizzata.

5. Tempo di creazione e dimensioni del pacchetto

Ora confrontiamo il tempo di build e le dimensioni del bundle tra Vite e Webpack, considerando la build di sviluppo, la modifica a caldo durante il server di sviluppo e la build di produzione.

Il nostro ambiente di test comprende:

  • Esecuzione dei test su MacBook Air con chip Apple M1 e GPU 8-core.
  • Un progetto Vue 3 di media scala che comprende 10 componenti e che utilizza Vuex per la gestione degli stati e Vue Router per il routing.
  • Inclusione di fogli di stile (CSS/SASS), risorse come immagini e font, oltre a un numero moderato di dipendenze.

Iniziamo con un confronto tra i tempi di bundling:

Vite [v4.4.11] Webpack [v5.89.0]
Prima compilazione Dev 376ms 6s
Hot Change Immediato 1.5s
Build prodotto 2s 11s

Vite emerge come chiaro vincitore per quanto riguarda la velocità di bundling, riducendo drasticamente i tempi di build. Sebbene Webpack offra configurabilità e solidi strumenti di sviluppo, impiega più tempo rispetto a Vite.

Vite [v4.4.11] (KB) Webpack [v5.89.0] (KB)
Dimensione del bundle di prodotti 866kb 934kb

Queste cifre si basano su un’applicazione Vue.js di medie dimensioni con un numero moderato di dipendenze. La dimensione effettiva del bundle può variare a seconda della complessità del progetto, delle dipendenze e delle tecniche di ottimizzazione.

Le ridotte dimensioni del bundle di Vite sono dovute all’efficiente pre-bundle con esbuild e ai moduli ES nativi.

La dimensione dei bundle di Webpack può essere ottimizzata attraverso varie opzioni di configurazione e plugin, ma in genere produce bundle più grandi grazie al suo processo di bundling completo.

6. Ottimizzazione della compilazione

Per quanto riguarda l’ottimizzazione del processo di compilazione nello sviluppo web moderno, Vite e Webpack offrono approcci distinti, ognuno con le proprie caratteristiche e capacità. Approfondiamo l’ottimizzazione della compilazione esplorando le principali differenze tra Vite e Webpack.

Generazione di direttive di precaricamento

Vite genera automaticamente le direttive <link rel="modulepreload"> per i chunk di ingresso e le loro importazioni dirette nell’HTML creato. Ciò migliora i tempi di caricamento precaricando in modo efficiente i moduli quando necessario.

Quindi, quando si ispeziona la pagina, potrebbe apparire come segue:

<!-- Vite - Module Preloading -->
<link rel="modulepreload" href="/module-a.js">

Webpack non supportava in modo nativo i suggerimenti del browser per le risorse. Ma a partire da Webpack v4.6.0, ha incluso il supporto per il prefetching e il preloading. L’uso di una direttiva inline durante la dichiarazione delle importazioni permette a Webpack di emettere un suggerimento per le risorse, che fornisce al browser informazioni su quando caricare il file importato. Ad esempio:

import(/* webpackPreload: true */ '/module-a.js');

Questo darà come risultato:

<!-- Webpack - Manual Module Preloading -->
<link rel="preload" as="script" href="/module-a.js">

Code splitting del CSS

Vite si distingue per il suo approccio semplificato alla suddivisione del codice CSS. Estrae automaticamente il CSS utilizzato dai moduli in blocchi asincroni e genera file separati. Ciò significa che solo il CSS necessario viene caricato tramite un tag <link> quando viene caricato il chunk async associato.

In particolare, Vite assicura che il chunk async venga valutato solo dopo il caricamento del CSS, evitando il Flash of Unstyled Content (FOUC). Poiché questa funzione è preconfigurata, possiamo continuare a importare i file CSS senza ulteriori passaggi:

import './main.css';

Webpack offre flessibilità ma richiede una maggiore configurazione per la suddivisione del codice CSS. Permette agli sviluppatori di suddividere il CSS utilizzando vari plugin e opzioni di configurazione, come ad esempio mini-css-extract-plugin.

// Webpack - CSS Code Splitting
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

Code splitting e chunks loading

Il code splitting è una tecnica fondamentale utilizzata per dividere il codice in parti più piccole e gestibili, caricando solo ciò che è necessario e quando è necessario. Questa pratica riduce significativamente i tempi di caricamento iniziale e conserva le risorse.

L’approccio di Vite al Chunking

Ci sono casi in cui Vite utilizza Rollup per suddividere il codice in pezzi separati automaticamente, come nel caso del caricamento dinamico o dei punti di ingresso multipli, e c’è un modo per indicare esplicitamente a Rollup quali moduli suddividere in pezzi separati tramite l’opzione output.manualChunks.

Oltre alla funzione di suddivisione del codice preconfigurata, Vite supporta anche le importazioni dinamiche con le variabili:

const module = await import(`./dir/${kinsta}.js`)

Vite permette anche agli sviluppatori di dividere i moduli dei venditori utilizzando l’opzione ufficiale splitVendorChunkPlugin():

import { splitVendorChunkPlugin } from 'vite'
export default defineConfig({
  plugins: [splitVendorChunkPlugin()],
})

Con tutte le importazioni dinamiche e la suddivisione del codice, è comune che il codice sia strutturato in moduli o chunk e che alcuni di questi moduli siano condivisi tra diverse parti di un’applicazione web. Vite riconosce i moduli comuni e ottimizza il processo di caricamento. Per capire meglio questo aspetto, vediamo un esempio tratto dalla documentazione ufficiale di Vite.

Un diagramma mostra più chunk che dipendono l'uno dall'altro e uno di essi è richiesto in due chunk.
Un grafico che mostra i chunk comuni richiesti in due chunk asincroni. (Fonte immagine: Vite)

Senza l’ottimizzazione, quando un utente apre una sezione di un’applicazione web, chiamiamola sezione A, che si basa sul codice condiviso Common Chunk C, il browser inizia a recuperare la sezione A. Durante l’analisi della sezione A, si rende conto di aver bisogno del Common Chunk C. Questo richiede un ulteriore giro di rete, che può rallentare il caricamento iniziale della pagina:

Entry (Section A) ---> async chunk A ---> common chunk C

Vite, invece, utilizza una sofisticata funzione chiamata Async Chunk Loading Optimization. Non aspetta che il browser scopra le sue esigenze, ma si prepara in modo proattivo. Quando un utente richiede la sezione A, Vite invia simultaneamente sia la sezione A che il Common Chunk C. Questo recupero parallelo dei chunk richiesti accelera notevolmente il processo di caricamento:

Entry (Section A) ---> (async chunk A + common chunk C)

Tuttavia, non si ferma qui. Il Common Chunk C potrebbe avere delle dipendenze, che potrebbero causare ulteriori viaggi di andata e ritorno in uno scenario non ottimizzato. Vite non trascura questo aspetto. Analizza rigorosamente queste dipendenze, assicurandosi che tutto ciò che è necessario, indipendentemente dalla sua profondità, venga caricato in modo efficiente in una sola volta. Questo elimina la necessità di ulteriori viaggi di rete, garantendo un’applicazione web altamente reattiva.

L’approccio async chunk loading di Vite ottimizza il processo di caricamento recuperando e servendo in modo proattivo tutti i pezzi di codice necessari in parallelo. L’eliminazione di ulteriori viaggi di rete si traduce in un’esperienza web più veloce. È come fornire al browser un itinerario di viaggio ben preparato, assicurando che riceva tutte le risorse necessarie senza inutili ritardi.

L’approccio di Webpack alla suddivisione del codice

Per quanto riguarda Webpack, sono disponibili tre tecniche generali per la suddivisione del codice:

  1. Punti di ingresso: questo è il modo più semplice per dividere un pezzo di codice. Possiamo semplicemente definire un nuovo punto di ingresso nel file di configurazione e Webpack lo aggiungerà come pezzo separato:
    const path = require('path');
     module.exports = {
      mode: 'development',
      entry: {
        index: './src/index.js',
        another: './src/separate-module.js',
      },
       output: {
        filename: '[name].bundle.js',
         path: path.resolve(__dirname, 'dist'),
       },
     };

    Tuttavia, questo approccio ha dei limiti. Se i moduli vengono importati in diversi punti di ingresso, finiscono in entrambi i bundle, con conseguente duplicazione del codice. Inoltre, non è molto adattabile per dividere la logica dell’applicazione principale quando necessario.

  2. Prevenire la duplicazione: un altro approccio consiste nell’utilizzare le dipendenze di entry o SplitChunksPlugin per dividere i pezzi, il che aiuta a ridurre la ridondanza. Ecco un esempio di come possiamo configurare la suddivisione del codice usando le dipendenze di entry:
    const path = require('path');
    
     module.exports = {
       mode: 'development',
       entry: {
         index: {
           import: './src/index.js',
           dependOn: 'shared',
         },
         another: {
           import: './src/another-module.js',
           dependOn: 'shared',
         },
         shared: 'lodash',
       },
       output: {
         filename: '[name].bundle.js',
         path: path.resolve(__dirname, 'dist'),
       },
      optimization: {
        runtimeChunk: 'single',
      },
     };
  3. Importazioni dinamiche: infine, Webpack supporta le importazioni dinamiche, una funzione preziosa per il caricamento del codice su richiesta. Utilizza una sintassi conforme alla proposta ECMAScript per le importazioni dinamiche. Questo metodo è più flessibile e granulare e si adatta a diversi scenari di suddivisione del codice.
    const { default: _ } = await import('lodash');

    Possiamo anche utilizzare i Magic Comments di Webpack per impostare un nome per il chunk, eseguirne il lazy-loading, specificare le esportazioni del modulo e impostare una priorità di recupero:

    import(
      /* webpackChunkName: "my-chunk-name" */
      /* webpackMode: "lazy" */
      /* webpackExports: ["default", "named"] */
      /* webpackFetchPriority: "high" */
      'module'
    );

Tree-Shaking

Il tree-shaking è una tecnica di ottimizzazione fondamentale che sia Vite che Webpack utilizzano per ridurre le dimensioni dei vostri bundle JavaScript.

Vite utilizza Rollup, che non solo permette di utilizzare i moduli ES, ma analizza staticamente il codice importato. Ciò significa che Vite può escludere le parti di un modulo che non usiamo, riducendo così le dimensioni dei bundle. Ad esempio, se abbiamo un modulo con più funzioni ma ne usiamo solo una, Vite includerà nel bundle solo quella funzione. Ecco un semplice esempio:

  • Senza l’uso dei moduli ES, se vogliamo importare ajax da ./utils.js, dovremmo importare l’intero file.
    const utils = require('./utils');
    const query = 'Kinsta';
    // Use the 'ajax' method of the 'utils' object
    utils.ajax(`https://api.example.com?search=${query}`).then(handleResponse);
  • L’uso dei moduli ES, invece, permette di importare solo ciò che serve, ottenendo così librerie e applicazioni più leggere, più veloci e meno complesse. Poiché Vite utilizza le dichiarazioni esplicite import e export, può eseguire un tree-shaking molto efficace senza affidarsi esclusivamente a un minificatore automatico per individuare il codice inutilizzato.
    import { ajax } from './utils';
    const query = 'Kinsta';
    // Call the 'ajax' function
    ajax(`https://api.example.com?search=${query}`).then(handleResponse);

Infine, per Vite possiamo utilizzare le opzioni preconfigurate di Rollup per il tree-shaking.

Anche Webpack supporta il tree-shaking, ma con un meccanismo diverso. Analizza le dipendenze del codice e rimuove le parti inutilizzate durante il processo di raggruppamento. Sebbene sia efficace, potrebbe non essere così completo come l’approccio di Vite, soprattutto quando si gestiscono moduli o librerie di grandi dimensioni.

Inoltre, secondo la documentazione di Webpack, è possibile contrassegnare i file come privi di effetti collaterali per garantire che non rimuova alcun codice che abbia un altro codice in produzione che si basa su di esso.

Il modo per farlo è la proprietà sideEffects package.json:

{
  "name": "kinsta-app",
  "sideEffects": false
}

Vale la pena notare che un’opzione di configurazione simile per definire gli effetti collaterali esiste anche nelle opzioni di Rollup di Vite.

7. Gestione delle risorse statiche

Le risorse statiche, come immagini, font e altri file, sono parte integrante dello sviluppo web. Vite e Webpack affrontano la gestione di questi asset in modo diverso, ognuno con i propri punti di forza e le proprie ottimizzazioni.

La gestione degli asset di Vite

L’approccio di Vite alla gestione degli asset statici è snello ed efficiente. Quando importiamo un asset statico, Vite restituisce l’URL pubblico risolto quando viene servito. Ad esempio, quando importiamo un’immagine come questa:

import kinstaImage from './kinsta-image.png';

Durante lo sviluppo, imgUrl verrà risolto in /img.png. Nella versione di produzione, diventerà qualcosa come /assets/img.2d8efhg.png, ottimizzato per la cache e le prestazioni.

Vite può gestire queste importazioni con percorsi pubblici assoluti o relativi, rendendolo flessibile per le esigenze del progetto. Questo comportamento si estende anche ai riferimenti URL nei CSS, che Vite gestisce senza problemi.

Inoltre, se utilizziamo Vite in un Single File Component (SFC) di Vue, i riferimenti alle risorse nei template vengono automaticamente convertiti in importazioni, semplificando il flusso di lavoro di sviluppo.

La gestione degli asset di Vite si spinge ancora oltre, rilevando i tipi di file di immagini, media e font più comuni, che vengono trattati come asset. Queste risorse sono incluse nel grafico delle risorse della build, ricevono nomi di file con hash e possono essere elaborate dai plugin per l’ottimizzazione.

La gestione degli asset di Webpack

Webpack, invece, ha un approccio diverso alla gestione degli asset statici. Con Webpack, importiamo le risorse come facciamo di solito:

import kinstaImage from './kinsta-image.png';

Webpack elabora l’importazione aggiungendo l’immagine alla directory di output e fornendo l’URL finale dell’immagine. In questo modo è facile lavorare con gli asset e funziona anche all’interno del CSS utilizzando url('./my-image.png'). css-loader di Webpack riconosce questo file come locale e sostituisce il percorso con l’URL finale dell’immagine nella directory di output. Lo stesso vale quando si utilizza html-loader per <img src="./kinsta-image.png" />.

I moduli Asset di Webpack introdotti nella versione 5 possono gestire diversi tipi di risorse, non solo le immagini. Ad esempio, possiamo configurare Webpack per gestire i file di font:

module.exports = {
  module: {
    rules: [
      {
        test: /.(woff|woff2|eot|ttf|otf)$/,
        type: 'asset/resource',
      },
    ],
  },
};

Questa configurazione permette di incorporare i font nel progetto tramite una dichiarazione @font-face.

8. Supporto per i siti statici

I siti statici offrono numerosi vantaggi, come tempi di caricamento rapidi, maggiore sicurezza e hosting semplificato. Un sito statico è composto da HTML, CSS e JavaScript e offre un’esperienza utente semplificata e una distribuzione efficiente dei contenuti. Sia Vite che Webpack possono aiutare gli sviluppatori a generare siti statici performanti, ma non con la stessa efficienza.

L’approccio di Vite alla generazione di siti statici

Vite offre istruzioni dedicate alla creazione di siti statici, sfruttando il suo approccio semplificato allo sviluppo e alla distribuzione, particolarmente adatto ai siti statici.

Un’altra caratteristica interessante di Vite è che dispone di uno script preview, che aiuta gli sviluppatori a lanciare la loro build di produzione in locale per vedere il risultato finale della loro applicazione in azione. Questa funzione permette agli sviluppatori di testare e vedere in anteprima la loro build di produzione prima di distribuirla su un server live.

Tuttavia, è importante notare che lo script preview di Vite è destinato all’anteprima della build in locale e non è pensato per fungere da server di produzione. Ciò significa che è un ottimo strumento per gli sviluppatori per testare le loro applicazioni prima della distribuzione, ma non è adatto per ospitare un sito di produzione live.

{
  "scripts": {
    "preview": "vite preview --port 3000"
  }
}

Vale la pena sottolineare VitePress, uno degli strumenti più potenti dell’ecosistema Vite. VitePress è un generatore di siti statici (SSG) che permette di generare rapidamente siti web incentrati sui contenuti. VitePress prende il testo sorgente basato su Markdown, applica un tema e produce pagine HTML statiche che possono essere distribuite rapidamente e gratuitamente su Kinsta.

L’approccio di Webpack alla generazione di siti statici

Sebbene Webpack non sia stato progettato specificamente per la generazione di siti statici, può essere utilizzato per creare siti statici attraverso vari plugin e configurazioni. Tuttavia, il processo è generalmente più complesso e meno snello rispetto a Vite: l’obiettivo principale di Webpack è quello di raggruppare e ottimizzare i moduli JavaScript, il che lo rende uno strumento potente per la creazione di applicazioni web complesse.

9. Supporto per il rendering lato server

Il Server-Side Rendering (SSR) è una tecnica di sviluppo web che esegue il rendering delle pagine web sul server e invia l’HTML completamente renderizzato al browser del cliente. Confrontiamo i due bundler in termini di supporto SSR:

  • Vite: Vite supporta il Server Side Rendering, offrendo un approccio semplificato per le applicazioni che richiedono SSR. Con Vite è possibile integrare senza problemi framework front-end in grado di eseguire la stessa applicazione in Node.js, pre-renderizzarla in HTML e successivamente eseguirne l’hydrate sul lato client. Questo rende Vite una scelta eccellente per le applicazioni che richiedono funzionalità SSR, fornendo agli sviluppatori gli strumenti necessari per ottimizzare le loro applicazioni renderizzate dal server.
  • Webpack: anche Webpack può essere utilizzato per il Server Side Rendering. Tuttavia, l’implementazione dell’SSR con Webpack tende a essere più complessa e richiede una conoscenza più approfondita della configurazione e dell’impostazione. Gli sviluppatori potrebbero dover investire ulteriore tempo per configurare l’SSR con Webpack rispetto all’approccio più snello offerto da Vite.

.

10. Supporto JSON

Sia Vite che Webpack supportano l’importazione di file JSON. Tranne che in Vite, l’importazione di nomi JSON è supportata anche per facilitare il tree-shaking.

// import an object
import json from './example.json'
// import a root field as named exports.
import { test } from './example.json'

11. Vue.js e supporto JSX

Vue.js, un importante framework JavaScript, segue la sintassi SFC (Single File Component), semplificando il processo di creazione delle interfacce utente. Al contrario, JSX è un’estensione della sintassi JavaScript, utilizzata principalmente in React, che consente agli sviluppatori di definire le strutture dell’interfaccia utente utilizzando tag ed elementi simili a quelli dell’HTML.

Vite offre un supporto di prim’ordine a Vue.js con plugin ufficiali che integrano perfettamente Vite con Vue. Gestisce anche i file JSX (.jsx e .tsx) grazie alla trasposizione di esbuild. Gli utenti di Vue.js possono utilizzare il plugin @vitejs/plugin-vue-jsx, creato su misura per Vue 3, che offre funzionalità come HMR, risoluzione globale dei componenti, direttive e slot.

Nei casi in cui JSX viene utilizzato con altri framework come React o Preact, Vite permette di configurare jsxFactory e jsxFragment personalizzati tramite l’opzione esbuild. Questo livello di flessibilità è prezioso per i progetti che richiedono la personalizzazione di JSX.

// vite.config.js
import { defineConfig } from 'vite'

export default defineConfig({
  esbuild: {
    jsxFactory: 'h',
    jsxFragment: 'Fragment',
  },
})

D’altra parte, Webpack non supporta in modo nativo Vue.js o altre librerie o framework specifici. Gli sviluppatori devono installare i caricatori e le dipendenze pertinenti per configurare un progetto per un framework JavaScript moderno, rendendo il processo più manuale e potenzialmente complesso.

12. Supporto per TypeScript

Vite offre un supporto nativo per TypeScript, consentendo di incorporare senza problemi i file di .ts nei progetti. Utilizza il transpiler esbuild per una rapida trasformazione del codice durante lo sviluppo. Vite si concentra sulla trasposizione, non sul controllo dei tipi. Si aspetta che l’IDE e il processo di compilazione gestiscano il controllo dei tipi.

Webpack non supporta nativamente TypeScript, quindi gli sviluppatori devono configurare manualmente TypeScript utilizzando il compilatore typescript e il file ts-loader. Questo richiede la configurazione di tsconfig.json per specificare le opzioni di TypeScript. Una volta configurato, Webpack utilizza ts-loader per compilare il codice TypeScript. Se da un lato questo introduce ulteriori passaggi di configurazione, dall’altro offre flessibilità e compatibilità con le altre funzioni di Webpack.

13. Supporto all’importazione di Glob

Vite supporta il Glob Import. Questa funzione viene utilizzata per importare più moduli dal file system tramite import.meta.glob function:

const modules = import.meta.glob('./kinsta/*.js')

Questo darà come risultato:

const modules = {
  './kinsta/isCool.js': () => import('./kinsta/isCool.js'),
  './kinsta/isAwesome.js': () => import('./kinsta/isAwesome.js'),
  './kinsta/isFun.js': () => import('./kinsta/isFun.js'),
}

Vite supporta anche Glob Import As, per importare i file come stringhe utilizzando import.meta.glob. Ecco un esempio di codice:

const modules = import.meta.glob('./kinsta/*.js', { as: 'raw', eager: true })

Che verrà trasformato in questo:

const modules = {
  './kinsta/rocks.js': 'export default "rocks"n',
  './kinsta/rules.js': 'export default "rules"n',
}

{ as: 'url' } è supportato anche per il caricamento di risorse come URL.

Mentre Webpack richiede plugin aggiuntivi come webpack-import-glob-loader e glob-import-loader per eseguire le importazioni globali. Questi ultimi amplieranno questo aspetto:

import modules from "./test/**/*.js";

In questo:

import * as moduleOne from "./foo/1.js";
import * as moduleTwo from "./test/bar/2.js";
import * as moduleThree from "./test/bar/3.js";

var modules = [moduleOne, moduleTwo, moduleThree];

14. Supporto ai Web Worker

I Web Worker sono essenziali per eseguire attività pesanti in background senza bloccare la pagina web principale. Ecco come Vite e Webpack li gestiscono:

Vite semplifica l’uso dei Web Worker. Si crea un file Web Worker separato, lo si importa nel codice principale e si comunica con esso. Vite offre due modi per importare un worker nel codice principale:

  1. new Worker() e i nuovi costruttori di SharedWorker():
    const worker = new Worker(new URL('./worker.js', import.meta.url));
    
    // OR
    
    const worker = new SharedWorker(new URL('./worker.js', import.meta.url));
  2. Importazione diretta con l’aggiunta di ?worker o ?sharedworker:
    import MyWorker from './worker?worker';
    
    const worker = new MyWorker();
    
    myWorker.postMessage('Hello from the main thread!');

    Webpack supporta anche i Web Worker e, a partire da Webpack 5, non è più necessario utilizzare un loader per utilizzare i worker.

    Const worker = new Worker(new URL('./worker.js', import.meta.url));

15. Capacità di sviluppo di librerie

Le librerie e i framework consentono agli sviluppatori di creare e condividere strumenti che accelerano lo sviluppo delle applicazioni web. Sia Vite che Webpack offrono soluzioni robuste.

Vite porta lo sviluppo di librerie a un livello superiore con la sua modalità Specialized Library, semplificando il processo di creazione di librerie incentrate sul browser. Inoltre, Vite offre la flessibilità di esternalizzare dipendenze specifiche, come Vue o React, che potremmo preferire non includere nel bundle di librerie.

Webpack, invece, è un bundler versatile che si rivolge anche agli autori di librerie. Se utilizziamo Webpack per creare una libreria JavaScript, possiamo configurarlo per soddisfare le nostre esigenze di bundle di libreria. Permette di definire il modo in cui il codice della libreria deve essere impacchettato, il che lo rende adatto alla creazione di un’ampia gamma di librerie.

16. Compatibilità con i browser

Vite dà la priorità ai browser moderni, puntando a quelli che supportano i moduli ES nativi, come Chrome >=87, Firefox >=78, Safari >=14 ed Edge >=88. I target personalizzati possono essere impostati anche tramite build.targeta partire da es2015. I browser tradizionali sono supportati da @vitejs/plugin-legacy.

Webpack supporta tutti i browser conformi a ES5 (escluso IE8 e successivi). Per adattarsi ai browser più vecchi, sono necessari dei polyfill per funzioni come import() e require.ensure().

In termini di compatibilità con i browser, entrambi sono ottimi, ma la scelta dovrebbe dipendere dal pubblico a cui è rivolto il progetto e dalle capacità del suo browser.

Riepilogo

Vite offre uno sviluppo rapidissimo con aggiornamenti veloci e ampie possibilità di personalizzazione grazie al suo approccio nativo ai moduli ES. Al contrario, Webpack, noto per la sua robustezza e l’ampio ecosistema, eccelle nelle build di produzione ma richiede una curva di apprendimento più ripida.

Quando dovrete scegliere tra Vite e Webpack, considerate le esigenze del progetto e la vostra familiarità con le complessità della configurazione. Entrambi hanno i loro vantaggi, quindi scegliete in base ai requisiti specifici del vostro progetto.

Infine, se state pensando di ospitare i vostri progetti basati su Vite, potete esplorare l’Hosting di Siti Statici di Kinsta, che offre una soluzione robusta ed efficiente per gli sviluppatori web.

Condividete il vostro bundler preferito e le considerazioni principali che hanno guidato la vostra scelta nella sezione commenti qui sotto.

Mostafa Said

I’m Mostafa, a full-stack developer with a knack for all things Laravel, Inertia, and JavaScript frameworks. When I'm not coding, you can find me sharing my knowledge through tutorials, diving into hackathons (and winning a few), and spreading the love for tech by teaching what I've learned.