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:
- Pas plus de 214 caractères
- Ne peux pas commencer par
.
ou_
- Lettres minuscules seulement
- les caractères spéciaux autorisés sont les lettres chiffres, et séparateurs (
-
,_
)
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
ounode
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 sectionengines
)
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.
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