Node Package Manager (npm)

Aujourd’hui, toutes les librairies et frameworks JavaScript s’installent avec npm. C’est un outil central qu’il faut bien maîtriser

Vous trouverez d’autres guides et une explication plus générale ici.

Package manager ?

Un package manager est un gestionnaire de dépendances. npm permet d’installer toutes les librairies, frameworks et outils dont a besoin un projet JavaScript.

C’est l’équivalent de Composer en PHP, Maven en Java, et NuGet en C#.

Node ?

L’outil s’appelle Node Package Manager car il a au départ été inventé pour Node.js. Mais aujourd’hui, npm est devenu le package manager pour tout l’écosystème JavaScript, y compris hors Node.js.

Installation de npm

Il suffit donc d’installer Node pour installer npm. Vous pouvez utiliser les installeurs du site officiel ou passer par d’autres outils comme Homebrew sur Mac.

Restez sur la version LTS, pour éviter les soucis.

Il est important d’avoir un npm à jour. Pensez donc à mettre à jour Node (et donc npm) régulièrement. Cela doit être le cas sur tous les postes de l’équipe.

Comme il s’agit d’écriture disque de milliards de fichiers, il est indispensable d’avoir un poste avec une configuration matérielle adaptée, le plus important étant d’avoir un disque dur SSD. Pour vous donner un ordre d’idée, installer un projet Angular prend moins d’une minute avec un disque dur SSD, tandis que cela pourra prendre 15 minutes ou plus sur un vieux disque dur.

Installation des dépendances

Le premier rôle d’un package manager est de permettre d’installer automatiquement toutes les dépendances (et leurs sous-dépendances) d’un projet.

Les dépendances sont décrites dans le package.json :

Il suffit alors pour tout installer dans lancer dans un terminal la commande npm install.

Corrélation avec Git ou SVN

Les dépendances sont toutes installées dans le répertoire node_modules (toujours pour des raisons historiques, cela ne veut pas dire que le projet est un projet Node.js).

Comme il s’agit de milliards de fichiers, parfois de plusieurs centaines de Mo, cela vous permet d’exclure ce répertoire de votre système de versioning (Git, SVN ou autre).

Il faut en revanche commiter le package.json et le package-lock.json.

Ajout d’une nouvelle dépendance

  • Dépendance de production : npm install rxjs
  • Dépendance de développement : npm install typescript -D

Semantic versioning

Les versions des dépendances suivent le principe du semantic versioning. Ce sont les versions à 3 nombres : 1.0.0.

L’idée est qu’une librairie ne passe pas à la version 2.0.0 quand elle le souhaite, parce qu’elle a ajouté plein de nouveautés et qu’elle veut faire le buzz. Cela suit des règles techniques :

  • passage à 1.0.1 = patch : correction de bugs, rétro-compatible
  • passage à 1.1.0 = mise à jour mineure : ajout de fonctionnalités, mais toujours rétro-compatible
  • passage à 2.0.0 = mise à jour majeure : cassure de rétro-compatibilité, même minime

Ce n’est donc pas une question de quantité de changements : si une seule ligne au milieu d’un milliard de lignes de code a changé et qu’elle casse la rétro-compatibilité, il faut passer à 2.0.0.

C’est pour cela qu’aujourd’hui tous les outils sortent des mises à jour majeures fréquemment : cela ne doit pas inquiéter. Cela ne veut pas dire qu’il s’agit d’une refonte complète de l’outil.

Souvent, cela peut même ne pas vous concerner du tout. Exemple : TypeScript est une dépendance d’Angular. Si Angular veut pouvoir utiliser les nouveautés d’une nouvelle version de TypeScript, cela en fait une nouvelle mise à jour majeure pour Angular, car c’est un nouveau pré-requis. Mais cela ne signifie pas que vous allez devoir modifier quoi que ce soit dans votre code.

Mises à jour des dépendances

Il faut bien sûr mettre à jour ses dépendances régulièrement. Vous pouvez faire le point avec la commande npm outdated.

Le semantic versioning permet de faciliter ces mises à jour. Si la commande npm update est lancée, npm fera automatiquement les mises à jour patchs et mineures, puisqu’elles sont rétro-compatibles !

C’est cela que signifie l’accent circonflexe devant les versions : ^1.0.0.

npm ne fera en revanche pas automatiquement les mises à jour majeures, car cela pourrait casser votre projet. Cela ne veut pas dire qu’il ne faut pas les faire, mais il faut le faire manuellement, en précisant la nouvelle version souhaitée : npm install rxjs@6. Puis tester.

Il existe d’autres signes, à éviter le plus possible, pour gérer des exceptions (des librairies qui respectent mal le semantic versioning). ~1.0.0 signifie que seules les mises à jour patchs seront faites lors d’un npm update. TypeScript est l’une des principales exceptions concernées.

package-lock.json

Le semantic versioning est génial pour faciliter les mises à jour, mais si c’était le même système qui était utilisé pour l’installation des dépendances, cela risquerait d’entraîner des problèmes, car tout le monde dans une équipe n’aurait pas forcément exactement la même installation.

C’est à cela que sert le package-lock.json. C’est un descriptif exact de l’installation du projet, afin qu’elle soit exactement la même sur tous les postes. Ne touchez pas à ce fichier : il est mis à jour automatiquement à chaque fois que vous ajoutez, supprimez ou mettez à jour une dépendance. Il faut par contre penser à le commiter.

Autres fonctionnalités de npm

npm permet tout un tas d’autres choses que vous pourrez explorer dans la documentation officielle.