Patcher un code JS sur son propre code

Les librairies open sources sont très pratiques pour ne pas avoir à développer à nouveau des fonctionnalités sur lesquelles d’autres développeurs ont déjà réfléchi. Il suffit de l’importer dans le projet, d’initialiser facilement la librairie, et l’ajout est en place. Cette librairie continue à être développée et amélioré et c’est très facile de récupérer ces améliorations et en profiter instantanément. Cependant, ça peut arriver qu’une librairie ne soit plus mise à jour. Elle ne bénéficie plus de correctifs de sécurité par exemple. Si ses dépendances évoluent, elle reste coincée à son état actuel.
C’est le soucis auquel je fus confronté en mettant à jour mon site personnel.

Explication du problème

Sur la page d’accueil, j’ai un petit carousel qui fonctionne avec la librairie tiny-slider. C’est une librairie que j’ai beaucoup utilisé dans le passé parce qu’elle est très petite en taille et fonctionnelle. Cette librairie permet d’afficher un carousel très simple en quelques lignes de code seulement. Elle a été crée fin 2015 et pendant quelques années à eu son petit succès. Par contre depuis 2019, elle n’est plus maintenue. Les issues s’accumulent ainsi que les pull requests. C’est le signe que la librairie est abandonnée par son créateur.

Graphique montrant le nombre de commit sur la librairie tiny-slider, avec un déclin fort depuis 2019.

J’utilise tiny-slider avec Sass. Sauf que Sass à évolué depuis 2019, et que certaines pratiques ne fonctionnent plus avec les dernières version. Par exemple, Sass n’autorise plus l’utilisation du signe de division dans son language, mais force l’utilisation de math.div, comme expliqué dans l’article : Breaking Change: Slash as Division. Par contre le code Sass de tiny-slider utilise encore ce signe dans son code qui à l’époque était encore d’actualité. Mais depuis le breaking change de Sass, il n’est plus compatible avec les dernières versions de la librairie.

Ce qui m’empêchait même de compiler mon code front. Pas question de changer de librairie de slider juste pour une histoire de division. Comment faire donc pour continuer à utiliser tiny-slider mais utiliser la version à jour de Sass ?

La solution : patch-package

Premièrement : corriger le soucis

L’avantage de la méthode que je présente, c’est qu’elle permet de modifier directement à partir des fichiers de librairies directement disponible dans le repertoires node_modules. Ce qui permet de facilement voir si le soucis est reglé.

J’ai donc directement modifié le fichier node_modules/tiny-slider/src/tiny-slider.scss qui posait soucis. J’ai juste changé la façon dont la division était utilisée puis je sauvegarde le fichier dans son état actuel.

Deuxièmement : générer un patch

Une fois que j’ai modifié mon fichier, j’installe cette librairie dans mes dépendances de développement.

npm install patch-package -D

Et je configure mon package.json en ajoutant la ligne ci-dessous pour que le patch soit bien appliqué a chaque installation des sources.

"scripts": {
    "postinstall": "patch-package"
}

Ensuite je n’ai plus qu’à lancer la command patch-package avec npx

npx patch-package tiny-slider

Maintenant, si vous regardez le code source de mon site, vous pouvez voir un dossier patches contenant un seul fichier tiny-slider+2.9.4.patch. Le contenu de ce fichier est très court ; il contient seulement les 3 lignes de changements nécessaires pour faire fonctionner Sass et Tiny-slider ensemble. C’est un fichier de diff qui montre donc les différences entre deux versions de code :

diff --git a/node_modules/tiny-slider/src/tiny-slider.scss b/node_modules/tiny-slider/src/tiny-slider.scss
index 40de1c1..3392a7d 100755
--- a/node_modules/tiny-slider/src/tiny-slider.scss
+++ b/node_modules/tiny-slider/src/tiny-slider.scss
@@ -1,5 +1,7 @@
 // Version: 2.9.4
 
+@use "sass:math";
+
 .tns-outer {
   padding: 0 !important; // remove padding: clientWidth = width + padding (0) = width
   [hidden] { display: none !important; }
@@ -121,7 +123,7 @@ $perpage: 3;
     overflow: hidden;
   }
   &-ct {
-    width: (100% * $count / $perpage);
+    width: math.div(100% * $count, $perpage);
     width: -webkit-calc(100% * #{$count} / #{$perpage});
     width: -moz-calc(100% * #{$count} / #{$perpage});
     width: calc(100% * #{$count} / #{$perpage});
@@ -133,7 +135,7 @@ $perpage: 3;
       clear: both;
     }
     > div {
-      width: (100% / $count);
+      width: math.div(100%, $count);
       width: -webkit-calc(100% / #{$count});
       width: -moz-calc(100% / #{$count});
       width: calc(100% / #{$count});

Troisièmement : commiter et appliquer automatiquement le patch

Une fois que c’est fait, je n’ai plus qu’à commiter ce fichier pour qu’il soit accessible depuis le repository, et que npm postinstall puisse le trouver lors de l’installation des librairies sources.

Grâce à l’ajout de la ligne dans le package.json, lorsque la commande npm install est lancée, le patch sera automatiquement appliquée. Ce qui veut dire que je peux aussi utiliser cette solution dans mon process de déploiement automatisé. Normalement npm installerait la version de tiny-slider trouvée sur le repository NPM sans mon patch appliqué. C’est ce qu’il fait puis il ajoute mon patche par la suite, résultant dans un code qui compile.

A faire attention

D’après le repository du package : https://www.npmjs.com/package/patch-package, les points à faire attentions sont :

  • Il est facile d’oublier de lancer npm lorsque l’on passe d’une branche à une autre qui contient des fichiers de correctifs.
  • Les correctifs de longue durée peuvent être coûteux à maintenir s’ils affectent une partie du code qui est mise à jour régulièrement et que vous voulez mettre à jour le package régulièrement aussi.
  • Les gros changements peuvent être difficiles à examiner.
  • Les modifications peuvent également avoir un impact sur le comportement d’autres package non modifiés.

Conclusion

Cette méthode est très pratique pour patcher un petit bout de code sur une librairie qui n’est plus mise à jour et que j’utilise encore. C’est une partie du code qui ne change pas, et qui ne va pas changer souvent. Plutôt que de devoir chercher, installer, test, coder avec une nouvelle librairie, je peux directement patcher l’existant.
L’avantage de cette solution est aussi de pouvoir modifier les fichier directement là où ils se trouvent dans le contexte ou je suis. Ca facilite beaucoup le débuggage et la vérification de l’efficacité du patch.


Commentaires

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *