logo

 

Introduction au package.json, npm install

package.json

Introduction au package.json, npm install

Une des raisons de la popularité de JavaScript comme langage est son système de modules, au point que cela est aussi une des critiques récurrentes de ce langage. Plusieurs registres existent, mais le mastodonte pour node.js est npm et son registre de plus de deux millions de modules.

Ces modules sont identifiés et configurés par un fichier, le package.json, qui est donc au cœur de l’écosystème Node.js dans son ensemble, et plus largement est une part conséquente de l’écosystème JavaScript.

Ce fichier est pourtant relativement méconnu, et utilisé uniquement pour lister les dépendances du projet, dans cette série d’articles, nous explorerons donc toutes les propriétés de ce fichier, leurs fonctions, et comment vous pouvez en prendre avantage, que vous travailliez sur un projet fermé qui ne sera jamais publié, un projet interne publié sur le registre privé de votre entreprise ou un projet open source que vous rendrez public.

Contenu

Préambule

Dans le langage courant, npm désigne à la fois le client npm et le registre npm. Nous serons donc prudents quand à distinguer les usages en précisant “registre npm” pour parler du registre, et en utilisant npm sans descriptif pour parler du client.

Le client et le registre sont d’ailleurs suffisamment distincts pour que de multiples clients alternatifs existent tout en gardant le même registre (yarn, pnpm…). Ces clients utilisent aussi le package.json sans changement, et ne changent donc rien au contenu de l’article.

Dans cet article, nous nous concentrerons sur les champs que npm propose de configurer lors de l’utilisation de la création d’un module (npm init)

package name

La première question que npm demande lors de la création d’un module est le nom, qui sera stocké dans la propriété name. Celle ci déterminera son nom dans le registre lors de la publication, mais aussi la manière de l’importer dans le code (soit via require('mon-module'), soit via import MonModule from 'mon-module').

Quelques règles sont à respecter lors du choix du nom:

L’organisation de npm a quelques recommandations optionnelles de:

  • Ne pas prendre le nom d’un module cœur de node.js.
  • Ne pas intégrer js ou node dans le nom, puisqu’un module npm est par définition un module javascript, et un autre champs existe pour préciser que le module est pour node (la section engines)

Il est aussi possible d’utiliser un scope, il s’agit d’un espace de noms qui sera sous votre contrôle, et permet de configurer des règles de publication spécifiques à cet espace.

Pour cela, la norme est simplement de nommer son module @mon-scope/mon-module.

Si vous voulez publier ce module, vous devrez vous assurer que vous avez réservé ce scope auprès du registre npm, mais vous pouvez aussi configurer votre client npm pour utiliser un registre privé pour ce scope uniquement par exemple.

version

La seconde propriété vitale lors de la publication de votre module est la version. Elle doit être changée pour chaque publication, et une fois un module publié avec un numéro de version, ce numéro de version ne peux plus être réutilisé, même si cette version du module est supprimée, il faudra publier avec une nouvelle version.

Cette propriété doit respecter la norme SemVer, et est donc de la forme 1.2.3, qui pour cette exemple indique une version majeure de 1, version mineure 2, et version patch 3.

La version majeure change lors de changements cassant de l’API, la version mineure lors de changement de l’API, et la version patch lors d’une nouvelle version ne comportant pas de changement sur l’API.

Par exemple:

  • La suppression de certaines fonction exposées par le paquet se feront avec un changement de version majeure
  • La dépréciation sans suppression ou l’ajout de nouvelles fonctions exposée se feront avec un changement de version mineure
  • Les mises à jour de dépendances ou les mises à jour de sécurité se feront avec un changement de version patch

Pour éviter de manipuler le fichier à la main, npm propose différentes commandes pour modifier la version:

$ npm pkg get version   # Affiche la version actuelle
"1.2.3"
$ npm version patch     # Nouvelle version patch
v1.2.4
$ npm version minor     # Nouvelle version mineure
v1.3.0
$ npm version major     # Nouvelle version majeure
v2.0.0
$ npm pkg get version   # Affiche la version actuelle
"2.0.0"
$ npm pkg set version="2.1.9"   # Permet de définir directement la version

description

Si vous faites une recherche de module sur le registre npm, vous verrez une courte description des modules trouvés, cette description est définie dans cette propriété.

Celle ci est complètement optionnelle, et est simplement une ligne de texte.

repository

Cette question permet de remplir la propriété repository, et lors de l’exécution de npm init est implicitement comprise comme un dépôt git. Il convient d’indiquer le lien du dépôt de code utilisé pour stocker votre module, git n’est cependant pas obligatoire, et les monorepo sont supporté.

Il existe deux formats pour ce champ, le plus complet est un objet aux propriétés type et url. type permet d’indiquer si le dépôt est git ou svn, url est le lien du dépôt tel que compris par l’utilitaire (git ou svn):

"repository": {
  "type" : "git",
  "url" : "https://github.com/npm/cli.git"
}
"repository": {
  "type" : "svn",
  "url" : "https://v8.googlecode.com/svn/trunk/"
}

Si votre module est stocké dans un monorepo, vous pouvez aussi ajouter une propriété directory pour indiquer sa place dans le monorepo:

"repository": {
  "type" : "git",
  "url" : "https://github.com/facebook/react.git",
  "directory": "packages/react-dom"
}

La seconde syntaxe possible est une simple ligne de texte, mais ne fonctionne que si vous utilisez GitHub, GitHub gist, Bitbucket, ou GitLab (instance publique), et permet de n’indiquer que le nom du projet dans le site:

"repository": "github:utilisateur/projet"
"repository": "gist:identifiant"
"repository": "bitbucket:utilisateur/projet"
"repository": "gitlab:utilisateur/projet"

keywords

Similaire à la description, ce champ optionnel permet d’indiquer les mots clefs qui devraient permettre de trouver votre module lors d’une recherche sur le registre. La différence est qu’il s’agit d’une liste de mots-clefs et non d’une seule ligne de texte.

author

L’auteur (ou autrice) du module, cette propriété est optionnelle et sera stockée sous la forme d’un objet aux propriétés name, url et email. Seul name est requis:

{
  "name" : "Barney Rubble",
  "email" : "b@rubble.com",
  "url" : "http://barnyrubble.tumblr.com/"
}

Il est aussi possible de la stocker sous une forme simplifiée, en une ligne de texte:

"Barney Rubble <b@rubble.com> (http://barnyrubble.tumblr.com/)"

contributors

Si il y a plusieurs auteurs (ou autrices) au module, il ne faut plus utiliser la propriété author mais contributors, qui utilise le même format, mais est une liste et permet donc d’indiquer les différentes personnes ayant contribué au module.

license

La licence sous laquelle ce module sera publié. Une note importante est que par défaut, cette propriété est définie à ISC, qui est une licence open source

Le format à utiliser est un identifiant de licence SPDX, ou UNLICENSED pour un module propriétaire.

Si un simple identifiant SPDX n’est pas suffisant, par exemple pour indiquer une double licence, il est possible d’utiliser une expressions SPDX:

"LGPL-2.1-only AND MIT AND BSD-2-Clause"

"GPL-2.0-or-later WITH Bison-exception-2.2"

Si vous voulez définir votre propre licence, vous pouvez aussi utiliser la valeur SEE LICENSE IN <filename>, avec filename le nom du fichier incluant la licence complète.

Notes

Certains points ont été simplifié dans cet article pour faciliter la compréhension. Cette section est là pour expliciter ces points dans leur intégralité.

Les caractères autorisés dans les noms

La règle exacte telle que définie par npm est:

The name ends up being part of a URL, an argument on the command line, and a folder name. Therefore, the name can’t contain any non-URL-safe characters.

Qui pourrait être traduit en:

Le nom sera utilisé dans une l’url, comme argument de ligne de commande, et comme nom de dossier. Ainsi, le nom ne peut pas contenir de caractère qui ne soit pas utilisable dans une URL.

La règle n’est donc en fait pas que seuls certains caractères sont autorisés, mais que les caractères “non-sur” dans une url sont interdits. Les caractères dits « non-sur’ sont défini par la RFC 3986. Couplés aux besoins d’être compatible avec la ligne de commande et les noms de dossiers, dans la pratique, les noms respectent la règle telle que citée dans l’article.

SemVer

La documentation npm précise bien que ce n’est pas tant la norme SemVer officielle mais la norme semver telle qu’implémentée dans le module node-semver

Ainsi, si il y a des différences entre la norme officielle et l’implémentation, c’est l’implémentation qui prime, une telle différence est par exemple que là où SemVer défini qu’il n’y a pas de caractère précédent le numéro, node-semver ignorera un = ou un v avant le numéro. Il est cependant recommandé de se baser sur SemVer.

module cœur de node js

Node.js définit dans son environnements certains modules “cœur” (core package), qui sont définis non pas dans node_modules, mais directement accessibles dans l’environnement node.

Pour node v18.13.0, cette liste est:

  • assert
  • async_hooks
  • buffer
  • child_process
  • cluster
  • console
  • constants
  • crypto
  • dgram
  • diagnostics_channel
  • dns
  • domain
  • events
  • fs
  • http
  • http2
  • https
  • inspector
  • module
  • net
  • os
  • path
  • perf_hooks
  • process
  • punycode
  • querystring
  • readline
  • repl
  • stream
  • string_decoder
  • sys
  • test
  • timers
  • tls
  • trace_events
  • tty
  • url
  • util
  • v8
  • vm
  • wasi
  • worker_threads
  • zlib