Ajouté par défaut dans tout projet JavaScript utilisant des modules npm, le package.json est un fichier de configuration bien souvent mis de côté. Pré-rempli par la CLI, un développeur n’a en effet pas vraiment besoin de le modifier.
Pourtant, le package.json possède des caractéristiques intéressantes, et offre une possibilité de personnalisation permettant d’améliorer l’expérience d’un développeur.
Vous ne connaissez que peu ce fichier de conf ? Vous voulez apprendre à le personnaliser ? Plongeons au coeur du package.json !
Qu’est-ce que le package.json ?
Un fichier de configuration obligatoire
Comme nous l’avons dit en introduction, le package.json est un fichier de configuration présent dans tout projet JavaScript utilisant des plugins node, par exemple en cas d’utilisation d’un framework. Que cela soit une techno back ou front, on le trouvera à la racine du projet.
Pour rentrer un peu plus en détails, le package.json est véritablement le coeur de tout projet utilisant node.
Il permet, comme nous le verrons, de définir les metadatas d’un projet, d’installer toutes ses dépendances, et d’exécuter les différents scripts npm.
La structure du fichier
Comme son extension l’indique, ce fichier de configuration est un objet JavaScript (JSON). Il contient donc, écrits en format ‘clé-valeur’, des sous-objets ou tableaux permettant de définir toutes les variables propres à un projet.
Aucun de ces éléments clé-valeur n’est requis ; il pourrait techniquement être un objet vide (bien que ce ne soit jamais le cas – il n’aurait aucune raison d’être, sinon).
Voyons en détails les différents éléments de ce fichier.
Les différents éléments du package.json
Pour expliquer les différentes valeurs définies dans un fichier package.json, basons-nous sur un exemple tiré de la documentation :
{
"name": "my-project",
"version": "1.0.0",
"description": "An example to show the package.json",
"main": "src/main.js",
"author": "Jon Doe jon@example.com <https://www.example.com>",
"licence": "ISC",
"private": true,
"bugs": "<https://github.com/whatever/package/issues>",
"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"start": "npm run dev",
"unit": "jest --config test/unit/jest.conf.js --coverage",
"test": "npm run unit",
"lint": "eslint --ext .js,.vue src test/unit",
"build": "node build/build.js"
},
"dependencies": {
"vue": "^2.5.2"
},
"devDependencies": {
"autoprefixer": "^7.1.2",
"babel-core": "^6.22.1",
"babel-eslint": "^8.2.1",
"babel-helper-vue-jsx-merge-props": "^2.0.3",
"babel-jest": "^21.0.2",
"babel-loader": "^7.1.1",
"babel-plugin-dynamic-import-node": "^1.2.0",
"babel-plugin-syntax-jsx": "^6.18.0",
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.0",
"babel-plugin-transform-runtime": "^6.22.0",
"babel-plugin-transform-vue-jsx": "^3.5.0",
"babel-preset-env": "^1.3.2",
"eslint": "^4.15.0",
"file-loader": "^1.1.4",
"jest": "^22.0.4",
"vue-jest": "^1.0.2",
"vue-loader": "^13.3.0",
"vue-style-loader": "^3.0.1",
"vue-template-compiler": "^2.5.2",
"webpack": "^3.6.0",
"webpack-bundle-analyzer": "^2.9.0",
"webpack-dev-server": "^2.9.1",
"webpack-merge": "^4.1.0"
},
"engines": {
"node": ">= 6.0.0",
"npm": ">= 3.0.0"
},
"browserslist": ["> 1%", "last 2 versions", "not ie <= 8"]
}
Et expliquons son contenu selon deux différents types d’éléments : ceux génériques, et ceux spécifiques.
Les éléments génériques
Commençons d’abord par expliquer les clés de cet objet qu’on retrouvera dans la plupart des projets.
name
Tout projet a logiquement un nom, et c’est ici qu’il sera ajouté dans le fichier de configuration. Cet élément est notamment obligatoire pour pouvoir publier un project sur npm.
Il doit respecter certaines règles :
- doit faire moins de 215 caractères ;
- ne doit pas inclure de majuscules ;
- ne peut pas contenir de caractère invalide dans une URL (car ce nom apparaîtra dans l’URL du package publié).
version
Également obligatoire pour toute publication npm, l’attribut version est le numéro de version actuel du projet. Souvent retrouvé au format x.y.z, il est à incrémenter à chaque nouvelle publication.
description
Logiquement, cet élément devra contenir la description du projet. Si vous voulez publier le package sur npm, cela sera notamment utile pour la recherche (npm indexant la description pour la recherche textuelle).
main
main est le point d’entrée du module. Si c’est un module exporté, c’est ce fichier qui sera chargé lors de l’import. S’il n’est pas défini, node cherchera par défaut un fichier ‘index.js’.
author
Ce champ contient les données concernant l’auteur du package. On le remplira souvent de la manière suivante : « Name {email} {url}”.
licence
L’attribut licence permet de définir le niveau d’open source accordé au module, ou plutôt à l’utilisation qui en sera faite. Pour savoir quelle licence accorder aux packages npm, il existe des sites tels que https://choosealicense.com/.
private
private n’est pas souvent présent, mais c’est un attribut intéressant à connaître. Setté à ‘true’, il empêchera la publication (accidentelle) du package sur npm.
scripts
La clé scripts a pour valeur un objet contenant un ensemble de commandes. Ces commandes seront exécutées, soit par le projet, soit manuellement par le développeur, pour effectuer des actions telles que :
- start, pour démarrer le projet localement ;
- test, pour lancer les tests définis ;
- build, commande qui compilera le projet pour le préparer au déploiement.
Il est important de noter, vous pouvez écrire vos propres scripts ici, afin de personnaliser les actions faites sur le projet (c’est par exemple utile lorsque l’on a plusieurs environnements de run différents).
bugs
Cette ligne contiendra l’URL vers laquelle rediriger un utilisateur s’il découvre un bug (le tracker d’issue GitHub, par exemple).
dependencies
L’objet dependencies contient toutes les dépendances externes dont a besoin le projet ou le module pour fonctionner. Npm installera ces dépendances en même temps que le module dans lequel se trouve le fichier de configuration courant. Cet objet sera notamment parcouru lors de l’utilisation de la commande d’installation ‘npm install’.
devDependencies
Les devDependencies définissent les dépendances utilisées uniquement lors du développement. C’est-à-dire qu’elles ne seront pas installées en cas d’utilisation de votre module comme dépendance externe. Elles ne sont utiles que lors de l’étape du développement et peuvent servir, par exemple, au build avant publication.
Les éléments spécifiques
Si les éléments présentés dans la section précédente peuvent être retrouvés dans tout projet JavaScript, il y a des attributs plus spécifiques.
On retrouve notamment dans les dependencies de l’exemple donné plus haut :
"dependencies": {
"vue": "^2.5.2"
},
"devDependencies": {
"vue-jest": "^1.0.2",
"vue-loader": "^13.3.0",
"vue-style-loader": "^3.0.1",
"vue-template-compiler": "^2.5.2",
},
Ce sont des dépendances spécifiques liées au framework JavaScript Vue.js. On les retrouvera uniquement dans un fichier de configuration de projets utilisant Vue.
De la même manière, on retrouvera des clés-valeurs spécifiques pour chaque framework, outil ou module.
Créer et gérer le package.json
Maintenant que nous avons compris le but et le fonctionnement de ce fichier de configuration, voyons comment le générer et le personnaliser.
Création d’un package.json
Si vous utilisez un framework ayant une CLI (command line interface) pour générer les projets, le package.json sera automatiquement créé.
Mais, si vous partez d’un projet vide et voulez gérer vous même toutes les dépendances, il est possible de créer soi-même le package.json. Cela se fait très simplement, avec cette commande à lancer dans un terminal, dans le dossier voulu :
npm init
Une série de questions sera posée, permettant la création d’un fichier de configuration avec les éléments de bases (nom, version, description, etc.).
Vous pouvez également générer un package.json qui remplira automatiquement tous ces champs génériques en fonction des données présentes dans le dossier courant. Cela se fait via la commande :
npm init --yes
Il existe d’autres utilisations possibles de la commande npm-init, voir la documentation officielle.
Personnaliser le package.json généré
Mais ce n’est pas tout ; il est également possible de personnaliser le package.json directement lors de sa création. Et ce de deux manières différentes : en définissant des valeurs par défaut et en ajoutant des questions lors de la création du fichier de conf.
Setter des valeurs par défaut
Il est en effet possible de définir des valeurs par défaut, pour override celles définies par npm. Cela se fait via la commande ‘npm config set <key> <value>’. Par exemple, pour définir la licence par défaut :
npm config set init-license "MIT" -g
La version par défaut et les données concernant l’auteur sont également modifiables.
Ajouter des questions de setup
L’autre façon de personnaliser le fichier package.json, c’est d’ajouter des questions à celles qui sont déjà posées lors de la commande ‘npm init’. Pour cela, il faut créer ou modifier le fichier de configuration général de npm, .npm-init.js. Pour le trouver, il faut exécuter cette commande :
npm config get init-module
Utilisez un éditeur de texte pour modifier ce fichier et y ajouter les éléments que vous voulez afficher lors de la commande ‘npm init’. Avec ces nouveaux éléments, votre .npm-init.js devrait ressembler à quelque chose comme :
module.exports = {
name: prompt('package name', basename || package.name),
version: prompt('version', '1.0.0'),
decription: prompt('description', ''),
main: prompt('entry point', 'index.js'),
keywords: prompt(function (s) { return s.split(/\\s+/) }),
author: prompt('author', ''),
license: prompt('license', ''),
repository: prompt('github repository url', ''),
customField: prompt('new value question', 'Default value'),
}
Une nouvelle ligne a été ajoutée à la fin de l’objet exporté : customField. À l’initialisation d’un fichier package.json, sa valeur sera demandée via le terminal.
Conclusion
Comme nous l’avons vu, le fichier package.json est à la base de tout projet utilisant npm. Plus qu’un simple objet JSON permettant de lancer des scripts, il a un rôle central dans le projet, et sa création peut être personnalisable, pour améliorer l’expérience de développement.
Connaissez-vous d’autres utilisations du package.json ? Dites-nous tout en commentaire !