Comprendre webpack dans un projet front-end JavaScript - Tuto

Comprendre le fonctionnement de webpack en 2021 dans un projet front-end JavaScript - Concepts & mise en place
JonathanM.jpg
Jonathan MOURIERMis à jour le 22 Oct 2021
tuto webpack

Si vous avez déjà touché un projet front-end embarquant du Sass, du Less ou encore avec un framework comme Vue.js, Angular ou React, vous avez sans doute déjà croisé ce groupeur de modules (modules bundler) plus connu sous le nom de webpack. Composé d'un ou plusieurs fichiers de configuration, il transforme nos fichiers sources précédemment cités en HTMLHTML (HyperText Markup Language) est un langage permettant de décrire le découpage d'une page web., CSSFeuilles de style qui permettent de mettre en forme des pages web. et JavaScriptLangage de scripting orienté objet minifiés. Mais qu'est-ce donc cette diablerie ? 

LesVisiteurs.gif

C'est ce que nous allons essayer de comprendre à travers cet article, car derrière cette magie, se cache un rouage bien ficelé et pas si compliqué à comprendre (car oui rien n'est magique en informatique, sauf les tests unitaires qui passent du premier coup).

Dans cet article, nous découvrirons les concepts de webpack, nous verrons ensuite comment initialiser un projet webpack et enfin un exemple pour compiler du Sass en CSS, mais avant de commencer :

webpack, c'est quoi ?

Nous pouvons voir webpack comme une petite usine. En entrée, nous ajoutons nos matières premières brutes (fichiers JavaScript, fichiers de style, images, polices ...). Notre usine prend ensuite ces matières premières et les transforme avec l'aide de différentes machines (loaders ou plugins), ce qui permet de sortir un produit fini qui sont nos assets statiques en HTML, CSS et JavaScript exécutables par n'importe quel navigateur (Internet Explorer je te vois dans le fond de la salle, tu sors). 

Webpack_ModuleBundler.png

Cette usine est tout simplement le fichier webpack.config.js et nos machines sont les dépendances ajoutées via le node package manager (npm). Les dépendances peuvent être ajoutées à la guise du développeur, ce qui permet une approche modulaire par rapport aux besoins de l'application.

Les concepts de webpack

Pour comprendre webpack, il faut d'abord comprendre ses concepts :

Entry concept

L'entry point, où le point d'entrée en français, spécifie le ou les fichiers qui serviront de "matières premières" à webpack. Avec ces fichiers, il construira ensuite son graphe de dépendances et déterminera ensuite à quels autres modules ou bibliothèques ces points d'entrées sont liés. Le point d'entrée par défaut est `javascript ./src/index.js mais nous pouvons très bien spécifier nos points d'entrées différemment comme dans l'exemple ci-dessous :

module.exports = {
    entry: {
        './src/styles/app.sass',
        './src/js/app.js',
        './src/index.pug',
    }
}

Output concept

L'output, comme son nom l'indique, signifie la sortie. Cette propriété indique à webpack où nos fichiers doivent être générés et comment il doit les nommer. Par défaut, le chemin configuré est ./public/main.js pour le fichier principal et tous les autres fichiers sont générés dans ce dossier javascript dist. Comme l'entrée, nous pouvons également personnaliser notre sortie, que ce soient les chemins ou les noms des fichiers :

const path = require('path');

module.exports = {
  entry: ...,
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'mon-app.bundle.js',
  },
};

Module & loaders concept

Ici, nous rentrons dans le noyau dur de webpack, le module et les loaders. Ce sont les machines qui vont permettre de traiter nos "matières premières". En dehors du bloc module, webpack comprend seulement le JavaScript et le JSON. Les loaders lui permettent de traiter d'autres types de fichiers et de les convertir en fichiers compréhensibles par l'application (en JavaScript) et donc de pouvoir ensuite l'ajouter à son graphe de dépendances.

Le bloc module contient un bloc rules qui requiert un tableau d'objets contenant 2 propriétés : test et use.

  • test identifie quels fichiers sont concernés par cette règle via une regex.
  • use indique quel(s) loader(s) doit être utilisé pour transformer ce type de fichier.

En fonction des loaders utilisés, des paramètres peuvent être obligatoire, il faudra alors se référer à la documentation du loader en question. Ci-dessous, un exemple de loader qui a pour rôle de sortir un fichier CSS minifié. Nous pouvons d'ailleurs voir que cette règle n'est applicable qu'aux fichiers CSS.

module.exports = {
    entry: ...,
    output: ...,
    module: {
        rules: [
            {
                test: /\.css$/,
                loader: 'css-loader',
                options: {
                    minimize: true,
                },
            }
        ],
    },
};

La liste des loaders disponibles

Plugins concept

Alors que les loaders sont utilisés pour transformer certains types de fichier, les plugins permettent de réaliser un plus large panel d'actions comme de l'optimisation, la gestion d'assets ou encore la gestion d'environnements de travail. Le loader ne peut traiter que du JavaScript, le plugin permet donc de réaliser ce qu'un loader ne peut pas faire !

Un plugin est un objet JavaScript qui possède une méthode apply. Une fois instanciée (cf. exemple ci-dessous), cette méthode est ensuite appelée par le compilateur de webpack, lui donnant ainsi accès à l'intégralité du cycle de vie de la compilation.

Mais qu'est-ce qu'on peut faire avec un plugin ?

Comme les loaders, voici une liste des plugins disponibles. La réponse est donc à peu prêt tout ! 😅 Mais comme une démonstration est toujours plus parlante que du blabla, prenons l'exemple du plugin Copy qui permet tout simplement de copier un fichier ou l'intégralité d'un dossier vers le dossier de build final (ou ailleurs si nous voulons).

const CopyPlugin = require("copy-webpack-plugin");

module.exports = {
    entry: ...,
    output: ...,
    module: ...,
    plugins: [
        new CopyPlugin({
           patterns: [
                { from: "source", to: "dest" },
                { from: "other", to: "public" },
            ]
        })
    ]
};

Le graphe de dépendances

Nous en parlons depuis le début, mais qu'est-ce que le graphe de dépendances ? Le graphe de dépendances est un graphe orienté qui indique comment les modules sont interconnectés entre eux. webpack va, dans un premier temps, analyser les modules qui sont présents et réaliser son propre graphe à partir des modules importés dans le fichier de configuration. Ce graphe regroupe ensuite tous ces modules en un petit nombre de bundle (simplification au maximum) pour qu'il puisse être chargé par le navigateur de manière optimale.

Tuto : comment initialiser un projet webpack ?

Rien de bien compliqué pour initialiser un projet webpack. Seul node.js est requis sur le poste de travail pour pouvoir démarrer.

Une fois notre dossier de projet créé, nous pouvons ouvrir un terminal et taper :

npm init -y 

Cette commande va créer et initialiser notre fichier package.json. Le projet initialisé, nous pouvons maintenant taper la commande suivante qui va installer webpack sur notre projet :

npm install webpack webpack-cli --save-dev

Créons maintenant l'arborescence de fichiers suivante :

webpack-demo
+ |- package.json
+ |- /dist
+ |- bundle.js
+ |- index.html
+ |- webpack.config.js
+ |- /src
+ |- index.js

Une fois nos fichiers créés, nous pouvons rédiger notre fichier de configuration webpack webpack.config.js pour que celui-ci ressemble à cela :

const webpack = require("webpack");
const path = require("path");

let config = {
    mode: 'development',
    entry: "./src/index.js",
    output: {
        path: path.resolve(__dirname, "./dist"),
        filename: "./bundle.js"
    }
}

module.exports = config;

À travers ce fichier de configuration, nous spécifions l'environnement de notre projet avec l'option mode : 'development', notre fichier d'entrée qui est notre index.js et enfin notre fichier de sortie situé dans le dossier dist./dist/bundle.js.

Ensuite, pour automatiser la compilation de nos fichiers, nous allons nous rendre dans notre fichier package.json et nous allons spécifier le script suivant :

  "scripts": {
    "watch": "webpack --watch"
  },

Enfin, nous n'avons plus qu'à lancer notre script dans une console à travers la commande suivante et webpack va automatiquement écouter nos fichiers sources pour les compiler à chaque modification :

npm run watch

Et c'est fini 😁 Quoi c'est tout ?! Notre usine est terminée oui, maintenant libre à vous d'ajouter les modules qui vous conviennent pour compiler du Sass ou des assets par exemple !

Exemple de compilation Sass

Mais, comme nous sommes sympa chez AXOPEN, nous allons tout de même vous donner un exemple de configuration pour compiler des fichiers Sass en CSS, la base quoi ! 😎

Pour commencer, ajoutons un dossier sass avec un fichier bundle.scss à notre dossier source. Nous devrions avoir l'arborescence suivante :

webpack-demo
+ |- package.json
+ |- /dist
+   |- bundle.js
+   |- index.html
+ |- webpack.config.js
+ |- /src
+   |- /sass
+       | - bundle.scss
+   |- index.js

Il faut ensuite ajouter les dépendances suivantes à notre projet :

  • Dart Sass (Sass) qui est l'implémentation du langage Sass
  • sass-loader, le module qui va permettre de compiler notre Sass en CSS
  • file-loader qui va nous permettre de générer un fichier CSS en sortie
npm install file-loader sass-loader sass --save-dev

Une fois nos dépendances installées, nous pouvons configurer notre fichier webpack.config.js :

Nous spécifions une deuxième entrée pour notre fichier Sass

entry: [
        "./src/index.js",
        "./src/sass/bundle.scss"
    ],

Nous ajoutons enfin nos deux loaders pour effectuer la transformation

    module: {
        rules: [
            {
                test: /\.scss$/i,
                use: [
                    {
                        loader: 'file-loader',
                        options: {
                            name: 'css/bundle.css',
                        }
                    },
                    // Compile le Sass en CSS
                    "sass-loader"
                ],
            },
        ],
    }

Attention, l'ordre des loaders est très important ! En effet, les loaders sont exécutés de la fin vers le début, c'est pour cela que le sass-loader se trouve en dernière position. Le Sass est d'abord transformé en CSS puis le résultat est ensuite transvasé dans le fichier de sortie qui est le bundle.css.

Enfin plus qu'à lancer notre commande npm run watch et tester notre configuration :

body {
  background-color: red;
  font-style: italic;
  div{
    background-color: purple;
  }
}

Vous devriez avoir le résultat suivant dans votre fichier CSS :

body {
  background-color: red;
  font-style: italic;
}
body div {
  background-color: purple;
}

Et voilà, notre compilateur Sass est en place ! Libre à vous ensuite d'ajouter des plugins de minification pour optimiser au mieux vos assets ! 👌

Et vous, que pensez-vous de webpack ?