Makina Blog

Le blog Makina-corpus

Surcharge thématique avec Webpack


Utiliser un loader pour surcharger à la volée des éléments de thème d'un projet Webpack.

Notre objectif

Imaginons un développement frontend proposant un certain nombre de fonctionnalités intéressantes. Une partie de son implémentation correspond à son thème graphique.

Nous souhaitons ré-utiliser ce développement, les fonctionnalités restant les mêmes, mais le thème en revanche doit être différent.

Les loaders Webpack

Les loaders Webpack sont des outils de transformation que Webpack appelle en fonction du type de ressources qu'il lit (par exemple, il va appeler le loader Sass pour transformer un fichier Sass en CSS).

Ils peuvent être chaînés (enfin de réaliser plusieurs transformations les unes à la suite des autres).

Et on peut écrire facilement ses propres loaders...

Écrire un loader

La structure d'un loader est très simple. C'est une fonction qui reçoit un contenu en entrée et qui doit renvoyer le contenu transformé:

module.exports = function(content) {
 this.cacheable && this.cacheable();
 return "<!-- contenu interdit -->";
};

On l'utilise en le déclarant dans notre webpack.config.js:

module.exports = {
...
 module: {
 loaders: [{
 test: /\.(html)$/,
 loader: "my-loader"
 }],
 ...

Dans cet exemple, nous avons construit un loader un petit peu radical (tous les fichiers .html sont remplacés par un commentaire mentionnant que le contenu est interdit).

Note: ici nous avons mis notre loader dans la section "loaders", mais il existe aussi les sections "preLoaders" et "postLoaders" qui, comme leurs noms l'indiquent, se déclenchent avant ou après la section "loaders".

Passer des paramètres au loader

Le loader peut accepter des paramètres en querystring. Par exemple, on peut l'appeler comme ceci:

loader: "my-loader?color=pink"

Et dans l'implémentation du loader on peut récupérer la valeur du paramètre "color" ainsi:

var loaderUtils = require("loader-utils");
module.exports = function(content) {
 ...
 loaderUtils.parseQuery(this.query).color;

Pitch

Pour travailler en asynchrone il y a plusieurs approches. Une des plus simples est d'utiliser la fonction "pitch". Elle nous permet de mettre dans une variable "data" des informations qui seront exploitables dans la fonction principale. Exemple:

module.exports = function(content) {
  return content + data.additionnal_part;
};

module.exports.pitch = function(remainingRequest, precedingRequest, data) {
  fs.readFile('./additional.txt', 'utf8', function (err, txt) {
    if(!err) { data.additionnal_part = txt; }
  });
};

Un loader pour surcharger le thème

Avec ces outils nous pouvons maintenant construire notre loader de surcharge thématique.

Nous avons donc créé un certain nombre de composants, chacun faisant des "require" vers des fichiers HTML ou CSS implémentant le thème. Et nous souhaitons maintenant remplacer ces fichiers à la volée lors du build par une version custom fournie dans un dossier spécifique.

Tout d'abord, pour agir sur les fichier css ou html, voici la config Webpack qu'il nous faut:

module: {
...
 preLoaders: [{
 test: /\.(html|css)$/,
loader: "theme-preloader?themepath=../customtheme"
 }],

Concernant l'implémentation, nous allons lire le paramètre "themepath" pour connaître le chemin du dossier fournissant le thème custom, et la fonction "pitch" va aller lire le fichier attendu s'il existe:

var fs = require('fs')
var loaderUtils = require("loader-utils");
var request = require('request');

module.exports = function(content) {
    this.cacheable && this.cacheable();
    return this.data.override || content;
};

module.exports.pitch = function(remainingRequest, precedingRequest, data) {
    this.cacheable && this.cacheable();
    var query = loaderUtils.parseQuery(this.query);
    var path = this.resourcePath
    var src_root = path.substring(0, path.lastIndexOf('/src/') + 1)
    var resource_path = path.substring(path.lastIndexOf('/src/') + 4);

    var newpath = src_root + query.themepath + resource_path;

    fs.readFile(newpath, 'utf8', function (err, newcontent) {
        if(!err) {
            console.log("OVERRIDE " + path + " WITH " + newpath);
            data.override = newcontent;
        }
    });
}

Et voilà !

Formations associées

Front end

Angular

Nantes Du 11 au 13 avril 2023

Voir la formation

Front end

Développement d'applications JavaScript

Distanciel (foad) Du 10 au 12 octobre 2023

Voir la formation

SIG/Web mapping

Leaflet

Toulouse Du 4 au 5 avril 2023

Voir la formation

Actualités en lien

Image
Symfony + Vue.js
21/06/2022 - 15:02

Créer une application Symfony/Vue.js

Pour faire des essais ou bien démarrer un nouveau projet, vous avez besoin de créer rapidement une application Symfony couplée avec un front Vue.js ? Suivez le guide !

Voir l'article
Image
Logo Cypress
11/10/2021 - 16:38

Retour d’expérience : tests fonctionnels avec Cypress

Dans le cadre d'un de nos projets de développement spécifique, l’équipe Makina Corpus a été amenée à coder un important logiciel métier avec de nombreuses entités et règles de gestion : l’Hydroportail.

Voir l'article
29/03/2019 - 15:28

Des boucles de composants génériques avec Angular

Ou comment faire des composants de listes réutilisables avec n'importe quel objet.

Voir l'article

Inscription à la newsletter

Nous vous avons convaincus