Introduzione a Webpack

pubblicato da , il 08/11/2018 alle 0:00

Web  Web - Front-end development 

Negli ultimi anni si è verificata una notevole evoluzione nel mondo dello sviluppo front-end che ha portato alla nascita di strumenti che potessero facilitare le fasi di build e minification delle applicazioni.
Tra tutti questi strumenti Webpack è diventato un tool fondamentale nella realizzazione di Single Page Application.

Webpack è un module bundler il cui utilizzo permette di sviluppare un'applicazione modulare e definire uno o più entry point da cui partire per generare i relativi bundle javascript; per generare i bundle, Webpack crea internamente un dependency graph: a partire dagli entry point definiti, Webpack percorre tutti gli import e include i moduli nel file javascript finale.

Installazione e configurazione

Per installare Webpack sono necessari NodeJS e npm.
Una volta installati, da un terminal (o da un prompt dei comandi) posizionandosi nella cartella root del proprio progetto, è sufficiente eseguire il comando:

npm install --save-dev webpack

Dalla versione 4 di Webpack è necessario installare anche la CLI con il seguente comando:

npm install --save-dev webpack-cli

È anche possibile installare Webpack globalmente lanciando:

npm install -g webpack

L'installazione globale è però sconsigliata, in quanto potrebbe causare problemi in presenza di progetti che utilizzano diverse versioni di Webpack stesso.

Una volta installato è necessario creare un file webpack.config.js in cui definire la configurazione che verrà utilizzata per la generazione dei bundle.
Creato questo file è possibile lanciare la compilazione con il comando webpack da un terminal.

Se il file di configurazione ha un nome diverso da webpack.config.js il comando per eseguire Webpack diventa webpack --config <nome del file>

Quali sono i concetti di base che ci permettono di configurare Webpack?

Per analizzare la struttura di Webpack prendiamo come esempio il seguente file:

module.export = {
    entry: {/* Qui definiamo gli entry point da cui partire per creare i bundles */},
    output: {/* Qui definiamo l'output dove salvare i bundles creati */},
    module: {
        rules: [/* Qui definiamo le regole con cui webpack compila i file per generare i bundles */]
    },
    plugins: [/* In questa sezione definiamo eventuali plugin */]
}

Come possiamo vedere, il file si divide in varie sezioni. Analizziamole una alla volta.

Entry

La sezione entry indica quali sono i moduli che Webpack utilizza come punti di partenza per generare i bundle.
Ci sono diverse modalità per configurare questa sezione. È possibile specificare un singolo file come stringa:

entry: './path/to/entry/file.js'

Oppure definire un oggetto per avere più di un bundle:

entry: {
    main: './path/to/main/file.js',
    vendor: ['./path/to/vendor1.js', './path/to/vendor2.js']
}

In questo ultimo esempio Webpack genererà due file di bundle i cui nomi corrisponderanno alle proprietà dell'oggetto entry (main e vendor).

Output

La sezione output specifica dove Webpack andrà a salvare i bundle generati.

const path = require('path');

module.exports = {
    output: {
       path: path.resolve(__dirname, './wwwroot'),
       filename: '[name].js'
    }
}

Le proprietà dell'oggetto specificato nell'output indicano il path in cui verranno salvati i bundle e il filename di ogni bundle.
Il placeholder [name] indica a Webpack che i bundle dovranno avere il nome delle proprietà specificate nell'oggetto entry (il valore di default è main)

Module e Rules

La sezione module permette di istruire Webpack sul modo di compilare i vari file per generare i vari bundle.
Tutte queste regole vanno specificate nell'array rules in questo modo:

module: {
    rules: [
        {
            test: /\.js%/,
            use: 'babel-loader'
        },
        {
            test: /\.(s)css$/,
            use: [
                'style-loader',
                'css-loader',
                'sass-loader'
            ]
        },
        {
            test: /\.(otf|woff|woff2|eot|ttf|svg)(\?|$)/,
            use: [
                {
                    loader: 'file-loader',
                    options: {
                        name: '[name].[ext]',
                        outputPath: 'fonts/',
                        publicPath: '../fonts'
                    }
                }
            ]
        },
        {
            test: /\.(jpg|jpeg|png)$/,
            use: [
                {
                    loader: 'file-loader',
                    options: {
                        name: '[name].[ext]',
                        outputPath: 'images/',
                        publicPath: '../images'
                    }
                }
            ]
        }
    ]
}

Ogni regola è formata da un test in cui viene indicata, tramite espressione regolare, la tipologia dei file a cui questa regola viene applicata ed una proprietà use che specifica che tipo di loader debba essere usato per compilare i file che soddisfano l'espressione regolare.
Un loader è un pacchetto npm (installabile tramite il comando npm install --save-dev <nome-del-loader>) che determina come Webpack debba compilare la tipologia di file interessata dalla regola.
Oltre al loader è possibile specificare alcune opzioni come il formato da dare al nome o la cartella specifica in cui salvare questo tipo di file.

Plugins

Le funzionalità di Webpack possono essere estese attraverso l'utilizzo dei plugin.
Un plugin è un pacchetto npm che aggiunge a Webpack funzionalità non previste nativamente, come ad es. l'ottimizzazione, la gestione degli asset o la generazione di file css.

È possibile installare un plugin tramite npm con il comando npm install --save <nome del plugin> e, una volta installato, importarlo nel nostro file webpack.config.js, tramite l'istruzione require('NomeDelPlugin').

Ad esempio, se volessimo estrarre un file CSS separato per ogni bundle, Webpack 4 consiglia l'utilizzo del plugin Mini css extract plugin.
Per installarlo utilizziamo npm in questo modo:

npm install --save-dev mini-css-extract-plugin

Una volta installato va importato nel file di configurazione di Webpack e aggiunto alla sezione plugins.

const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
    plugins: [
        new MiniCssExtractPlugin({
            filename: '[name].css'
        })
    ]
}

Una volta aggiunto ai plugin va istruito Webpack su come utilizzarlo per generare il file CSS desiderato. Per fare questo va aggiunto il loader alle regole che si occupano di gestire i fogli di stile:

module.exports = {
    module: {
        rules: [
            {
                test: /\.(s)css$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    'sass-loader'
                ]
            }
        ]
    }
}