NPM & Shrinkwrap

Cet article a pour vocation de faire découvrir une commande méconnue de NPM qui est shrinkwrap. Nous allons avoir que dans un context projet et surtout avec une équipe, cela a un sens important de l'intégrer dans son cycle de vie.

Petit rappel de ce qu'est la convention "semver"

Pour rappel, la numérotation d'un module NodeJs se repose sur la convention semver. Le principe est simple: nous avons une version basé sur trois chiffres, séparés par des points.

Le premier chiffre est le "major version". Cela veut dire que lorsque ce numéro change, nous avons un changement majeur dans le module, apportant potentiellement des "breaking changes". Donc en générale, quand nous mettons à jour un module dont le premier chiffre change, nous pouvons nous attendre à avoir à réadapter notre code.

Le second est le "minor version". En somme, c'est tout simplement une version stable. Mettre à jour un module dont seul le deuxième numéro change devrait poser peu de problèmes (tout dépend si le développeur respect le principe du semver :) ).

Et enfin le dernier est le "patch version". Alors, attention: danger. Cela veut dire que nous avons corriger un patch, et que du coup nous publions une version de correction. Mais cela n'induit pas forcément que nous n'allons pas importer d'autres bugs.

Du coup, faites bien attention quand vous mettez à jour un module dont seul la dernière version change (dans le monde Gulp, je peux vous assurer que j'ai eu de nombreux problèmes en voulant naïvement mettre à jour des modules où visiblement, des patchs avaient été appliqués).

En quoi shrinkwrap peut nous aider ?

Basiquement, shrinkwrap est une commande fournie par NPM qui va littéralement faire un "snapshot" des dépendances NodeJs présents dans votre répertoire "node_modules", et également des sous-dépendances !

En effet, par rapport au chapitre précédent, nous pourrions comme approche naïve de figer les versions des modules dans le "package.json". En enlevant par conséquence les "jokers" permettant de préciser si nous souhaitons une version proche, une version supérieure, inférieure, etc. Pour voir les possibilités de configuration, je vous invite à lire ce lien.

En revanche, nos modules peuvent avoir dans leur propre package.json des modules avec des versions qui ont ces fameux joker ! Du coup, potentiellement, nous pouvons par inadvertance télécharger une sous-dépendance plus récente. Et de ce fait, nous pouvons arriver à avoir entre développeurs et serveurs d'intégrations / de productions des répertoires node_modules inconsistants.

Cela peut amener une conséquence toute bête: des apports de bugs (et qui pour le coup, ne seront reproductibles que sur certains postes).

Comme je l'indiquais, la commande "npm shrinkwrap" va nous permettre de générer un fichier contenant les dépendances NodeJs et si nous le souhaitons, les "devDependencies" également. Cela va générer un fichier appelé "npm-shrinwrap.json".

Même si nous le générons automatiquement la plupart du temps, nous pouvons le faire "manuellement". L'intérêt par la suite est de modifier à la main le contenu de ce fichier si vous souhaitez surcharger la version d'un sous-module (car buggé et figé en dur dans le package.json d'un sous-module).

Un petit aperçu du contenu d'un fichier "npm-shrinkwrap.json" (vous pouvez aussi consulter ce lien: https://github.com/rochejul/gulp-angular-protractor/blob/master/npm-shrinkwrap.json):




Quel est le comportement de shrinkwrap ?

A chaque fois qu'une commande "npm install" est lancé, NPM va vérifié la présence du fichier "npm-shrinkwrap.json". Si ce dernier n'existe pas, nous aurons le comportement habituel. Autrement:

1) Si le fichier ne contient que les dépendances NodeJs (et pas celle de "devDependencies"), alors NPM va télécharger précisément ces modules, et télécharger / mettre à jours les modules décrits dans "devDependencies"

2) Si vous avez déclaré directement dans le package.json un nouveau module et que vous faites un "npm install", ce dernier ne sera pas téléchargé car non présent dans le fichier "npm-shrinkwrap.json"

3) Si vous avez généré le fichier "npm-shrinkwrap.json" avec les "devDependencies", la commande "npm install --production" qui normalement ne télécharge que ce qui est déclaré dans "dependencies" va quand même tout télécharger

4) Si vous "exposez" le fichier "npm-shrinkwrap.json" (par le biais de la propriété "files" du package.json), lorsque votre module sera téléchargé, NPM va lire le fichier et donc télécharger précisément les versions des modules.

5) Si vous ajouter l'option "--no-shrinkwrap" lors un "npm install", le fichier "npm-shrinkwrap.json" sera ignoré. A noter que les modules / sous-modules qui ont ce fichier ne seront pas affectés par cette option, et donc nous pourrons récupérer précisément les versions des modules.

6) A mes yeux, il n'est utile d'injecter les devDependencies dans le énpm-shrinkwrap.json" uniquement si nous n'avons que ça. Cela peut arriver lorsque nous avons des modules NodeJs d'applications Web frontend, ou quand nous faisons des outils pour nos projets.

Quelques commandes à connaître autour de shrinkwrap

npm prune

Cette commande va tout simplement éliminé tous les modules présents dans "node_modules" et qui ne sont pas déclarés dans le fichier "package.json".

Cette commande est importe. Autrement, une erreur sera levé lors de la génération du fichier "npm-shrinkwrap.json", car il trouvera une différence et ne saura pas la gérer.


npm shrinkwrap

Facile, cette commande va générer le "npm-shrinkwrap.json" avec tous les modules déclarés dans "dependencies" du fichier "package.json".

npm shrinkwrap --dev

Cette commande va non seuelement générer le "npm-shrinkwrap.json" avec tous les modules déclarés dans "dependencies" du fichier "package.json", mais aussi inclure les modules déclarés dans "devDependencies".


npm install --save --save-exact mymodule@version

Cette commande va non-seulement télécharger le module, mais aussi le rajouter en tant que "dependencies" dans le fichier "package.json" tout en ignorant les "semver jokers" (en figeant la version). Car par défaut, NPM rajout toujours un ">=" devant la version d'un module téléchargé.


npm install --save-dev --save-exact mymodule@version

Même chose qu'auparavant à ceci prêt que nous souhaitons le rajouter en tant que "devDependencies".


npm install --save --save-exact --no-shrinkwrap mymodule@version

Installe le module en ignorant le contenu du fichier "npm-shrinkwrap.json". Cela est important dans le cas d'une mise à jour. En effet, si "--no-shrinkwrap.json" n'est pas présent, alors NPM va lire le contenu du fichier, voir que le module est présent et nous empêcher de faire la mise à jour.


npm install --no-shrinkwrap

Nous ignorons purement est simplement le fichier "npm-shrinkwrap.json". Attention à cette commande: soyez bien sûre de ce que vous faiteS.


Comment utiliser shrinkwrap ?

Le but étant de lister les commandes à faire en fonction des actions souhaitées. Ici, nous ne gérons que le cas des modules pour "dependencies". Si vous souhaitez la même chose pour les "devDependencies", vous devez remplacer "--save" par "--save-dev" et "npm shrinkwrap" par "npm shrinkwrap --dev".

Mettre à jour complètement "node_modules" à partir de shrinkwrap

Cela peut être dû à une surcharge d'un sous-module, à une évolutions des versions des sous-modules, etc...

> rm –r node_modules
> npm install

Ajouter un nouveau module

> npm prune
> npm install --save --save-exact mymodule@moduleversion
> npm shrinkwrap

Supprimer un module

> npm prune
> npm uninstall --save mymodule
> npm shrinkwrap

Mettre à jour un module

> npm prune
> npm uninstall --save mymodule
> npm install --save --save-exact --no-shrinkwrap mymodule@newmoduleversion
> npm shrinkwrap


Changer la version de votre module

Vous voulez changer la version car vous apportez de nombreuses fonctionnalités. Vous devez regénérer alors le shrinkwrap, car celui-ci est associé à une version précises de votre module.

> npm prune

> npm shrinkwrap

Commentaires

Posts les plus consultés de ce blog

ISO: liens & outils utiles

NodeJs et SSL: une petite analyse

Créer sa commande slack en quelques minutes