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

Formations Front end

Formation Angular

Nantes Du 22 au 24 mai 2024

Voir la formation

Formations Front end

Formation Développement d'applications JavaScript

Toulouse Du 18 au 20 juin 2024

Voir la formation

Formations SIG / Cartographie

Formation Leaflet

À distance (FOAD) Du 1er au 2 juillet 2024

Voir la formation

Actualités en lien

Image
Capture d'une partie de carte montrant un réseau de voies sur un fond de carte sombre. Au centre, une popup affiche les information de l'un des tronçons du réseau.
28/02/2024

Géné­rer un fichier PMTiles avec Tippe­ca­noe

Exemple de géné­ra­tion et d’af­fi­chage d’un jeu de tuiles vecto­rielles en PMTiles à partir de données publiques.

Voir l'article
Image
Read The Docs
01/02/2024

Publier une documentation VitePress sur Read The Docs

À l'origine, le site de documentation Read The Docs n'acceptait que les documentations Sphinx ou MKDocs. Depuis peu, le site laisse les mains libres pour builder sa documentation avec l'outil de son choix. Voici un exemple avec VitePress.

Voir l'article
Image
Widget
04/04/2023

Créer une application en tant que composant web avec Stencil

Mise en place dans le cadre de Geotrek, cette solution permet de se passer d'une iFrame pour afficher une application dans n'importe quel site.

Voir l'article

Inscription à la newsletter

Nous vous avons convaincus