Prima applicazione Webpack

di Rocco Macellaro

Sviluppiamo una pagina web di base utilizzando pochi file, in particolare un file index.html che incorpora due file JavaScript: index.js e shopping-list.js. Il contenuto del file index.html sarà il seguente:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Prima applicazione Webpack</title>
  </head>
  <body>
    <h1>Prima applicazione Webpack</h1>
    <script src="./src/shopping-list.js"></script>
    <script src="./src/index.js"></script>
  </body>
</html>

Chiaramente, questa pagina HTML ha la sola funzione di visualizzare un titolo “Webpack First Application” e di importare due file JavaScript. È fondamentale notare l’ordine di importazione dei due file, in particolare il fatto che il file index.js viene importato dopo il file shopping-list.js. Torneremo a questo aspetto tra breve. Ora, procediamo completando il nostro codice di esempio inserendo il seguente nel file shopping-list.js:

function shoppingList() {
    console.log('Shopping list');
    
    const title = document.createElement('h2');
    title.innerHTML = "Lista della spesa";

    const body = document.querySelector('body');
    body.appendChild(title);
}

In questo file, è definita una funzione denominata createShoppingList, che, al suo interno, prima stampa la stringa “Shopping list” nella console. Successivamente, viene creato un elemento HTML di tipo h2 con il testo “Lista della spesa”. Infine, questo elemento appena creato viene inserito nel DOM della pagina, all’interno del corpo (body).

Infine il file index.js non fà altro che invocare la funzione shoppingList():

shoppingList();

Riprendendo quanto accennato in precedenza, è cruciale notare che se avessi importato prima il file index.js e successivamente il file shopping-list.js nella pagina HTML, l’applicazione sarebbe entrata in errore. Quando il browser avrebbe tentato di invocare shoppingList(), avrebbe restituito un messaggio del tipo: “shoppingList is not defined” (shoppingList non è definito). Questo accade perché il browser, al momento dell’esecuzione del contenuto di index.js, non è ancora a conoscenza della funzione shoppingList poiché è definita nel file importato successivamente.

In applicazioni più complesse, l’importanza dell’ordine di importazione dei file diventa evidente. Tuttavia, gestire manualmente l’ordine di centinaia di file, ove ognuno contiene funzioni richiamate in parti diverse dell’applicazione, può diventare un’operazione estremamente complicata. È qui che entra in gioco Webpack, Webpack può gestire tutte queste dipendenze per noi e raggrupparle comodamente in un solo pacchetto JavaScript che include tutto il codice necessario per l’applicazione, quindi non dovremo fare altro che includere questo pacchetto nella pagina, per questo motivo quello che faremo adesso è affidarci a webpack.

Installiamo webpack

Prima di procedere con l’installazione di Webpack, dobbiamo generare un file di configurazione per la nostra applicazione, chiamato package.json.

Il file `package.json` è un file di configurazione fondamentale in un progetto Node.js. Esso contiene informazioni sul progetto e le sue dipendenze, insieme a comandi personalizzati, script e metadati. Di seguito, riporto alcune delle sezioni più comuni e importanti che si trovano in un file `package.json`:

  • `name`: Il nome univoco del tuo progetto.
  • `version`: La versione attuale del tuo progetto.
  • `main`: Specifica il punto di ingresso principale dell’applicazione.
  • `dependencies`: Elenco delle dipendenze necessarie per l’esecuzione dell’applicazione in produzione.
  • `devDependencies`: Elenco delle dipendenze necessarie solo durante lo sviluppo.
  • `scripts`: Definisce comandi personalizzati e script che possono essere eseguiti utilizzando npm.
  • `description`, `author`, `license`, etc.: Altre informazioni rilevanti sul progetto.

Il file `package.json` facilita la gestione delle dipendenze, l’esecuzione di script e fornisce informazioni cruciali sul tuo progetto. Durante lo sviluppo, npm (Node Package Manager) utilizza questo file per installare le dipendenze specificate e per eseguire comandi personalizzati definiti negli script.

Quindi per creare questo file per il nostro progetto, possiamo utilizzare il seguente comando nel terminale:

npm init -y

Questo comando genera il file package.json con le impostazioni predefinite per la nostra applicazione. Ora possiamo procedere con l’installazione di Webpack utilizzando il comando:

npm install webpack webpack-cli --save-dev

In questo comando, stiamo installando due pacchetti. Il primo, webpack, è il pacchetto principale di Webpack, mentre il secondo, webpack-cli, è uno strumento da riga di comando utilizzato per eseguire Webpack direttamente dal terminale.

L’opzione –save-dev è utilizzata per aggiungere questi pacchetti come dipendenze di sviluppo nel file package.json. Se non hai installato webpack-cli in modo separato, il sistema te lo richiederà durante la prima esecuzione di Webpack.

al termine dell’installazione il nostro file package.json somiglierà a questo:

{
  "name": "first-application",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^5.90.1",
    "webpack-cli": "^5.1.4"
  }
}

come potete notare i due pacchetti di webpack sono state scaricate e installate come dipendenze “dev” da node.js ovvero dipendenze necessarie solo durante il processo di sviluppo ma non utilizzate per la realizzazione della build di produzione.

Per procedere con l’esecuzione di Webpack, dobbiamo apportare alcune modifiche alla nostra attuale base di codice. Innanzitutto, andiamo al file HTML e rimuoviamo uno degli script, shopping-list.js, poiché non è più necessario. Ecco come potrebbe apparire il tuo file HTML dopo la rimozione:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Prima applicazione Webpack</title>
  </head>
  <body>
    <h1>Prima applicazione Webpack</h1>
    <script src="./dist/main.js"></script>
  </body>
</html>

Posso notare che in questo nuovo codice viene importato un file chiamato main.js dalla cartella dist. Al momento, questa cartella non è ancora presente nel nostro codice, ma verrà generata quando eseguiremo il comando di compilazione di Webpack.

Per consolidare tutto il nostro codice in un unico file JavaScript, dobbiamo importare esplicitamente tutte le dipendenze necessarie. Iniziamo andando nel file index.js e importiamo la funzione ShoppingList dal file shopping-list.js. Prima di utilizzare la funzione createShoppingList, assicuriamoci di importarla.

import shoppingList from './shopping-list.js';

shoppingList();

Assicurati di salvare le modifiche al file index.js. Ora, tutte le funzioni e dipendenze necessarie sono importate nel file index.js, che diventa il punto di ingresso principale per l’applicazione.

Questa pratica di importare esplicitamente le dipendenze contribuisce a migliorare la chiarezza del codice e a gestire in modo efficiente le dipendenze nell’ambito del sistema di moduli di JavaScript.

Per garantire che il tutto funzioni correttamente, è necessario esportare esplicitamente la funzione createShoppingList dal file shopping-list.js. Per farlo, andiamo in questo file e aggiungiamo un’esportazione alla fine del codice.

function shoppingList() {
  console.log('Shopping list');

  const title = document.createElement('h2');
  title.innerHTML = "Lista della spesa";

  const body = document.querySelector('body');
  body.appendChild(title);
}

export default shoppingList;

Con questa modifica, stiamo esportando la funzione createShoppingList in modo esplicito dal file shopping-list.js. Ora il nostro sistema di moduli JavaScript è configurato correttamente, e possiamo procedere con l’utilizzo di Webpack per gestire il bundle di questi file.

La sintassi che stai utilizzando è legata ai moduli di JavaScript. I moduli rappresentano lo standard attuale per lavorare con il codice JavaScript in modo modulare e organizzato. Webpack supporta i moduli JavaScript di default e consente di gestire le dipendenze e creare bundle ottimizzati per le applicazioni web.

Ora, come indicato, possiamo procedere con l’esecuzione di Webpack. Nel terminale, esegui il seguente comando:

npx webpack

Questo comando utilizza il pacchetto webpack installato localmente nel tuo progetto (grazie alla configurazione in package.json). npx è uno strumento che consente di eseguire pacchetti Node.js senza doverli installare globalmente. Dopo aver eseguito questo comando, Webpack inizierà ad analizzare i tuoi file, gestirà le dipendenze e creerà un bundle ottimizzato.

Assicurati di aver salvato tutte le modifiche nei file prima di eseguire Webpack.

Dall’output nel terminale, sembra che l’esecuzione di Webpack sia avvenuta con successo. In questo caso, stiamo eseguendo Webpack senza una configurazione personalizzata. Sebbene Webpack 5 utilizzi la configurazione predefinita a meno che tu non ne fornisca una personalizzata, è generalmente consigliato fornire una configurazione specifica.

Solitamente, si crea un file di configurazione (webpack.config.js) per specificare molte opzioni utili in modo comodo e mantenibile, vedremo come creare una configurazione personalizzata nei prossimi articoli. Tuttavia, anche senza una configurazione personalizzata, Webpack funzionerà con una configurazione predefinita.

Dall’output sulla console, è evidente che l’opzione ‘mode’ non è stata impostata. La modalità è un’opzione speciale in Webpack che semplifica notevolmente la configurazione per gli ambienti di produzione e sviluppo. Approfondiremo le opzioni di modalità in altri articoli.

È positivo notare che Webpack ha generato un file chiamato main.js. Esploriamo il contenuto di questo file per comprendere meglio cosa è stato incluso. Webpack ha creato una cartella di output denominata dist. All’interno del file main.js, è probabile che tu trovi la versione minificata del tuo codice. La minificazione è una tecnica che riduce le dimensioni del file JavaScript rimuovendo spazi, commenti e utilizzando nomi di variabili più corti. Questa è una pratica comune per ottimizzare le risorse nelle applicazioni web.

È un’osservazione significativa notare come Webpack ha determinato il punto di ingresso del tuo progetto. Se scorrerai verso l’alto nell’output del terminale, noterai che Webpack menziona qualcosa riguardo al “punto di ingresso”. Il punto di ingresso è il file utilizzato come punto di partenza dagli utenti del pacchetto durante la creazione dell’applicazione. Di solito, questo file importa altri moduli dall’applicazione. In questo caso, Webpack presume che il punto di ingresso si trovi all’interno della cartella denominata src. Inoltre, poiché il nome del file non è specificato, Webpack userà index.js come punto di ingresso predefinito, situato all’interno della cartella src.

Ora, se apriamo il nostro file index.html in un browser, possiamo vedere che tutto continua a funzionare correttamente. Questo è possibile perché, come abbiamo notato, abbiamo importato il file main.js dalla cartella dist all’interno del nostro file index.html. Questo file main.js è stato creato da Webpack quando abbiamo eseguito il comando di compilazione.

Aggiungere una configurazione webpack

Per creare una configurazione personalizzata per Webpack, creeremo un file JavaScript denominato webpack.config.js. Questo file sarà situato nella cartella principale della nostra applicazione. Iniziamo a specificare la configurazione di base per Webpack.

Inizia a definire all’interno del file la configurazione di base. Webpack prevede che questo modulo esporti un oggetto di configurazione. All’interno di questo oggetto, possiamo specificare molte opzioni utili. Esploreremo molte di queste opzioni nel corso del nostro progetto. Per ora, definiamo il punto di ingresso, il file di output e la modalità.

// webpack.config.js

const path = require('path');

module.exports = {
  entry: './src/index.js',  // Punto di ingresso principale
  output: {
    filename: 'bundle.js',  // Nome del file di output
    path: path.resolve(__dirname, 'dist'),  // Percorso della cartella di output
  },
  mode: 'none',  // Modalità di sviluppo
};

In questo esempio, stiamo specificando che il punto di ingresso principale (entry) è ./src/index.js, il file di output (output) sarà chiamato bundle.js, e sarà salvato nella cartella dist del nostro progetto. La modalità (mode) è impostata su ‘none’ per il momento ne parleremo più approfonditamente in seguito.

Prima di compilare nuovamente con Webpack, cancelliamo eventualmente la cartella dist che è stata generata dall’esecuzione precedente di Webpack. Ecco un comando che puoi eseguire nel tuo terminale:

rm -rf dist

Se stai usando Windows, il comando per rimuovere la cartella potrebbe essere differente. Puoi anche utilizzare un’esploratore di file per eliminare manualmente la cartella dist.Dopo aver rimosso la cartella, eseguiamo nuovamente Webpack e verifichiamo se tutto funziona correttamente.

npx webpack

Dopo aver eseguito questi comandi, verifica che la cartella dist sia stata creata correttamente e che contenga il file bundle.js. 

Diamo un’occhiata all’interno della cartella dist. Come puoi notare, il nome del file bundle è diverso da quello predefinito. Ricordi che quando esegui Webpack senza configurazione, viene generato un file chiamato main.js, ma questa volta il nome di questo file è bundle.js. Come specificato nel file di configurazione, ciò indica che Webpack non sta più utilizzando la configurazione predefinita, ma sta invece adottando la configurazione personalizzata che abbiamo fornito.

Ogni volta che eseguiamo Webpack, viene creato un bundle JavaScript all’interno della cartella dist, adesso quindi nel nostro file index.html non dobbiamo più far riferimento al file main.js ma dobbiamo fare riferimento a questo bundle, quindi modifichiamo index.html come segue:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Prima applicazione Webpack</title>
  </head>
  <body>
    <h1>Prima applicazione Webpack</h1>
    <script src="./dist/bundle.js"></script>
  </body>
</html>

Questa corrisponde esattamente a quanto abbiamo specificato nel file di configurazione. Ora apriamo il browser e verifichiamo se la nostra applicazione continua a funzionare. Come puoi notare, l’applicazione è ancora operativa e sta attualmente utilizzando il codice generato da Webpack.

Per agevolare l’esecuzione di Webpack, possiamo aggiungere uno script nel file package.json. Se apri il package.json, noterai un elenco di script predefiniti. Attualmente, c’è solo uno script di test che non svolge alcuna operazione, generato automaticamente al momento della creazione del file JSON.

Per semplificare l’avvio di Webpack, aggiungeremo un nuovo script denominato “build”. Ogni volta che eseguirai questo script, Webpack si avvierà automaticamente.

Ecco come puoi modificare il tuo package.json:

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack"
},

Ora, quando desideri eseguire Webpack, puoi semplicemente utilizzare il seguente comando nel terminale:

npm run build

Questa è una pratica comune per semplificare l’utilizzo di strumenti come Webpack all’interno di progetti Node.js.

Nel prossimo articolo vedremo cosa gli asset module di webpack

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *