Node.js entre packages et modules
Bien que depuis 2013, Node.js ne s’appui plus sur le format de CommonJS, entre 2009 et 2013 cela fût le cas, et, la notion de chargement de modules reste un des points central au sein de Node.js. Donc lorsqu’on utilise Node.js il y a cet aspect important à prendre en compte qui est le chargement de packages et/ou de modules.
Packages vs Modules
Puisqu’ils sont au cœur du principe d’utilisation de Node.js, il est important de donner une définition claire et d’explorer ce que sont les modules et les packages.
- Un package est un ensemble de fichiers regroupés au sein d’un dossier qui contient un fichier package.json. Ce dossier peut être mis à disposition depuis une URL, tel quel ou compressé. Un package peut charger un ou plusieurs modules pour son propre fonctionnement.
- Les modules sont tout type d’éléments qui seront requis par l’instruction require(), qu’il s’agisse d’un package, ou d’un seul fichier JavaScript. Le plus simple reste de mettre en place quelques exemples d’illustrations. Un module peut charger un ou plusieurs package pour son fonctionnement.
Sur un de vos disques durs, ou clé USB, créez un dossier Projet-Node. Positionnez le pointeur de votre terminal (MacOS) ou l’invite de commande ou PowerShell (Windows) sur ce dossier et lancez le processus d’initialisation de projet, npm init -y
. En ajoutant l’argument -y
dans notre commande, nous demandons à NPM de créer une initialisation de projet avec toutes les valeurs par défaut.
Dans un article précédent, Prendre en main Node.js, nous avions vu que nous pouvions charger un fichier en particulier depuis la console et l’exécuter. Nous allons profiter de cet article pour comprendre l’ensemble des articulations entre Package et Modules.
CommonJS Modules
Les spécifications de cette API proposent deux éléments d’échange; entrée (require) et sortie (module.exports).
- Le premier, require(), est une fonction qui permet d’importer un module externe. Il suffit de passer un argument indiquant le chemin d’accès au module à charger, chemin aussi bien relatif (dossiers) qu’absolu (url). Si ce module est un fichier JavaScript, il n’est pas nécessaire d’indiquer l’extension et dans le cas de l’usage d’un chemin relatif, il faut bien comprendre que le module qui va être chargé ne se trouve pas nécessairement dans le dossier des modules de Node.js, il est donc nécessaire de préciser la référence relative au chemin
- / pour indiquer le dossier racine,
- ./ pour indiquer le dossier en cour,
- ../ pour préciser le dossier parent
- Le second est un objet, exports, qui est en fait la seule interface externe accessible de l’API. Cette objet peut contenir toutes propriétés et fonctions qui seront nécessaires pour utiliser correctement le module. Il existe parfois une confusion possible entre l’emploi de exports ou de module.exports. En fait, les deux sont identiques et pointent vers le même objet. Donc, exports n’est qu’un helpers de module.exports. Cependant, il est important de comprendre que lorsqu’on use du helpers exports, chaque propriétés ou fonctions est alors ajoutée à module.exports, sauf si celui ci a déjà été explicitement défini dans un autre type.
Pour éviter, toute confusion, mettons quelques exemples en place.
Depuis l’éditeur de code de votre choix, créez deux fichiers JavaScript. Nommez le premier base.js et le second code.js et enregistrez les dans le dossier projet. Placez les codes suivants dans chacun des fichiers;
base.js
var code = require('./code'); console.log('infos à la racine du fichier base.js'); code.a(); code.b();
code.js
console.log('infos à la racine du fichier code.js'); exports.a = function(arg){ console.log('infos interne à A'); } exports.b = function(arg){ console.log('infos interne à B'); }
Maintenant, exécutons base.js
Vous remarquerez, que l’ensemble des exécutions se réalise dans l’ordre des lignes de commandes. Ceci peut avoir son importance dès lors que vous invoquerez plusieurs modules, ou packages, au sein d’un même fichier. Une autre remarque à prendre en compte, et que si nous modifions le fichier code.js, en ajoutant exports='Une autre valeur';
sans spécifier de propriétés interne, les propriétés a et b ne seront alors plus accessibles.
Pour éviter ce genre d’erreur, il peut être préférable d’employer une syntaxe de type objet JSON pour définir les diverses propriétés et fonction du module.exports, mais attention cette fois-ci le helpers exports ne pourra pas être utilisé, il faudra avoir recours de manière explicite à module.exports. Pensez également à entourer chaque propriétés par des guillemets, et ce, même s’il s’agit de fonctions.
À l’instar des trois instructions JavaScript que nous venons de voir, require, module et exports, il existe deux autres propriétés qui peuvent parfois être utiles et qui sont __filename et __dirname, qui comme leurs noms l’indiquent renvoient respectivement le nom de fichier en cours d’exécution, et le dossier d’exécution. Créez un fichier variables.js, collez le code ci dessous et invoquez le depuis la console.
console.log(__filename); console.log(__dirname);
Des modules c’est bien, mais les packages alors ?
Comme nous l’avons vu au début de ce chapitre, un module peut être constitué d’un seul fichier JavaScript, ce que nous avons fait jusqu’à présent, mais il peut également contenir tout un package. Nous avons vu également qu’un package n’est en fait qu’un dossier contenant un fichier package.json, ou à défaut un fichier index.js. Donc faire appel à un fichier isolé, ou faire appel à un package, revient au même.
Commençons par mettre en place un package en parallèle de notre projet. Nous n’allons pas distribuer ce package mais le mettre à disposition localement afin de démontrer les principes de création et d’utilisation. Créons donc un dossier Projet-Node-Package au même niveau que notre dossier Projet-Node. Remarquez que bien que l’on puisse attribuer n’importe quel nom à ces dossiers, nous avons garder la même racine Projet-Node afin de les maintenir côte à côte dans l’arborescence du disque dur et ainsi de pouvoir simplifier leur localisation.
Dans le dossier Projet-Node-Package créez un fichier package.json par défaut (donc ayant une propriété main pointant vers index.js) et un fichier fichier-specifique.js. Ensuite depuis le dossier Projet-Node créez un fichier appel-package.js qui sollicitera l’appel à notre package. Notez au passage que le chemin d’accès emploie cette fois-ci ../ en début de chemin, afin de bien indiquer qu’il faut cette fois-ci remonter d’un niveau pour trouver le package. Vérifiez dans le tableau ci-dessous l’ensemble des codes propres à chacun des fichiers (notez que le fichier package.json a été réduit à son minimum pour éviter trop de verbosité).
package.json
{ "name": "Projet-Node-Package", "main": "index.js" }
appel-package.js
var code = require('../Projet-Node-Package'); code.infos();
fichier-specifique.js
module.exports = { "infos" : function(arg){ console.log('infos package'); } }
Depuis la console de commande, invoquez le fichier appel-package, vous devriez obtenir une erreur… modifiez la propriété main du fichier package.json du dossier Node-Projet-Package en l’affectant cette fois ci à fichier-specifique.js. Renouvelez l’opération d’appel vers le fichier appel-package depuis la console et cette fois ci tout devrait fonctionner comme attendu.
Nous pourrions également retirer le fichier package.json, et renommer le fichier fichier-specifique.js en index.js et cela fonctionnera tout aussi bien… donc comme nous l’avions évoqué plus haut, un package peut être un dossier contenant un fichier index.js ou bien contenant un fichier package.json qui a sa propriété main pointant vers le fichier de base.
1 réponse
[…] ds paquets afin d’en exploiter la magie. Je vous invite donc à passer à l’article Node.js entre packages et modules qui concerne l’utilisation de modules et de paquets et qui permet de mieux comprendre les […]