💡

Vous êtes en train de lire l’Annexe A du livre “Node.js”, écrit par Thomas Parisot et publié aux Éditions Eyrolles.

L’ouvrage vous plaît ? Achetez-le sur Amazon.fr ou en librairie. Donnez quelques euros pour contribuer à sa gratuité en ligne.

Cette annexe est une sélection de modules npm (npmjs.com) à laquelle vous référer pour démarrer rapidement, mais aussi pour découvrir des usages et des domaines d’application insoupçonnés.

J’ai bâti cette liste à partir de mon expérience personnelle et sur la confiance que je porte aux personnes à l’origine de ces modules.

💬
Remarque Versions de Node et npm

Le contenu de ce chapitre utilise les versions Node v10 et npm v6. Ce sont les versions stables recommandées en 2022.

💡
Pratique Jouer avec les exemples dans un terminal

Les exemples titrés d’un nom de fichier peuvent être installés sur votre ordinateur. Exécutez-les dans un terminal et amusez-vous à les modifier en parallèle de votre lecture pour voir ce qui change.

Installation des exemples via le module npm nodebook
npm install --global nodebook
nodebook install appendix-a
cd $(nodebook dir appendix-a)

La commande suivante devrait afficher un résultat qui confirme que vous êtes au bon endroit :

node hello.js

Suivez à nouveau les instructions d’installation pour rétablir les exemples dans leur état initial.

1. Boîte à outils du quotidien

Ces modules répondent à des besoins quotidiens, pour travailler plus rapidement sur des structures ECMAScript.

1.1. lodash

lodash (npmjs.com/lodash) est une collection de plusieurs dizaines de fonctions pour travailler plus facilement avec des chaînes de caractères, des tableaux, des fonctions et des objets.

Vous pourrez ainsi filtrer, sélectionner, fusionner, vérifier et composer de nouvelles variables, aussi bien pour Node que dans les navigateurs.

lodash.js
'use strict';

const { intersection, first } = require('lodash');
const DC = ['Batman', 'Brainiac', 'Thor'];
const Marvel = ['Spiderman', 'Thor'];

const result = first(intersection(DC, Marvel));
console.log(result);  // (1)
  1. Affiche Thor.

1.2. he

he (npmjs.com/he) est un utilitaire pour encoder et décoder des entités HTML dans des chaînes de caractères.

he.js
'use strict';

const {encode} = require('he');
const html = '<h1>Blog Post</h1>';

console.log(html);                   // (1)
console.log(encode(html));           // (2)
  1. Affiche <h1>Blog Post</h1>.

  2. Affiche &#x3C;h1&#x3E;Blog Post&#x3C;/h1&#x3E;.

1.3. chance

chance (npmjs.com/chance) crée des données de manière aléatoire. Le module retourne aussi des prénoms fictifs, mais aussi des numéros de téléphone, des nombres, des paragraphes, des dates d’anniversaire, des identifiants Android ou Apple, etc.

Il s’utilise surtout pour générer des données factices à des fins de tests, en attendant les vraies données.

1.4. date-fns

date-fns (npmjs.com/date-fns) est une collection de fonctions pour travailler avec des dates, plus facilement qu’avec l’objet natif Date.

Vous pouvez formater, ajouter ou retirer des jours, vérifier si deux périodes de temps se chevauchent ou si deux dates font partie d’une même semaine calendaire.

1.5. tcomb

tcomb (npmjs.com/tcomb) renforce la création de structures typées et non mutables. Cela réduit les effets de bord de nos applications lorsque les données n’ont pas la structure attendue.

tcomb.js
'use strict';

const t = require('tcomb');

const GPS = t.struct({                                // (1)
  lat: t.Number,
  lon: t.Number,
}, {strict: true});

const Bordeaux = GPS({ lat: 44.8638, lon: -0.6561 });
const Crest = GPS({ lat: 44.7311, long: 4.9861 });    // (2)
const Toulouse = GPS({ lat: 43.6008, lon: 'r0s3' });  // (3)
  1. Définition d’une structure stricte qui a pour propriétés lat et lon, pour latitude et longitude.

  2. Cet appel va lancer une exception car la propriété long est inconnue.

  3. Cet appel va lancer une exception car la propriété lon doit être un nombre.

1.6. eventemitter3

eventemitter3 (npmjs.com/eventemitter3) sert à gérer des événements de manière uniforme dans un script Node et dans les navigateurs.

eventemitter3.js
'use strict';

const EventEmitter = require('eventemitter3');
const emitter = new EventEmitter();

emitter.on('ping', data => console.log('on: %s', data));
emitter.once('ping', data => console.log('once: %s', data));

console.log(emitter.listeners('ping')); // (1)

emitter.emit('ping', ['ping', 'ping']); // (2)
emitter.emit('ping', ['pong']);         // (3)

emitter.removeListener('ping');
emitter.emit('ping', ['pong']);         // (4)
  1. Affiche [ [Function], [Function] ].

  2. Affiche on: ping,ping puis once: ping,ping.

  3. Affiche on: ping,ping.

  4. N’affiche rien, l’événement étant désormais déconnecté.

2. Pendant le développement

2.1. debug

debug (npmjs.com/debug) rend optionnel l’affichage de messages de débogage. Les messages s’affichent en présence d’une variable d’environnement. Nous pouvons ainsi lancer un processus et retracer un cheminement complexe de données.

Par défaut, les messages ne s’affichent pas :

node examples/debug.js

Les messages du débogueur app s’affichent désormais :

DEBUG=app node examples/debug.js
  app fromages [ 'livarot', 'chaource' ] +0ms

Nous pouvons en afficher plusieurs en même temps, en usant du caractère * ou en séparant les noms de débogueurs avec des virgules :

DEBUG=app* node examples/debug.js
  app fromages [ 'livarot', 'chaource' ] +0ms
  app:timer now 1531304027271 +0ms
debug.js
'use strict';

const debug = require('debug');
const log = debug('app');                     // (1)
const logInterval = debug('app:timer');       // (2)

log('fromages %o', ['livarot', 'chaource']);  // (3)

setTimeout(() => {
  logInterval('now %d', Date.now());          // (4)
}, 1000);
  1. Création du débogueur app.

  2. Création du débogueur app:timer.

  3. La fonction de débogage s’utilise de la même manière que console.log.

  4. Cette fonction fait appel au débogueur app:timer.

2.2. nodemon

nodemon (npmjs.com/nodemon) relance le processus actif dès qu’un fichier ECMAScript ou JSON est modifié. C’est un module exécutable particulièrement utile lorsque nous voulons prendre en compte les changements dans une application qui tourne en continu. C’est le cas des applications web, entre autres.

💬

Pour en savoir plus, rendez-vous à la section “Pendant le développement : relancer le serveur automatiquement” du chapitre 7.

2.3. npm-run-all

npm-run-all (npmjs.com/npm-run-all) est mon outil favori pour composer avec les scripts npm. Il a l’avantage d’être adaptable, de régler finement ce qui doit être exécuté en parallèle ou séquentiellement. Le module transfère les arguments aux sous-scripts.

package.json
{
  "...": "...",
  "scripts": {
    "build": "npm-run-all -p 'build:*' -s start",
    "build:css": "sass ...",
    "build:js": "browserify ...",
    "start": "node server.js"
  }
}

2.4. husky

husky (npmjs.com/husky) intègre Git aux scripts npm. Autrement dit, vous pouvez déclencher des scripts lors d’événements Git, lors d’un push, avant un commit ou après avoir rapatrié des changements.

package.json
{
  "...": "...",
  "scripts": {
    "precommit": "lint-staged",
    "post-merge": "npm install"
  }
}

La liste complète des hooks Git se trouve dans la documentation officielle : git-scm.com/docs/githooks.

2.5. onchange

onchange (npmjs.com/onchange) observe une liste de fichiers en continu et déclenche une commande dès que l’un d’entre eux est modifié. C’est particulièrement utile pour reconstruire automatiquement des fichiers de configuration ou des fichiers front-end pendant le développement.

package.json
{
  "...": "...",
  "scripts": {
    "build:css": "sass ...",
    "dev": "npm-run-script -p 'watch:*' start",
    "watch:css": "onchange '**/*.scss' -- npm run build:css",
    "start": "node server.js"
  }
}

2.6. tiny-lr

tiny-lr (npmjs.com/tiny-lr) est une implémentation minimale du protocole livereload (livereload.com). Il s’intègre à un serveur HTTP ou à une application Express pour relayer la liste des fichiers modifiés côté client.

Le script ou l’extension navigateur client remplace les anciens fichiers par les nouveaux pour refléter les changements sans recharger la page.

2.7. livereactload

livereactload (npmjs.com/livereactload) recherche les composants React à chaud, c’est-à-dire sans rafraîchir la page ni perdre l’état des données. C’est un module indispensable pour développer des applications front-end réactives.

💬

Rendez-vous dans la section “Changements en temps réel dans le navigateur” du chapitre 9 pour en savoir plus sur son installation et son intégration.

3. Protéger nos applications

Le code que nous écrivons se protège dès la conception et dans le temps. Certains modules filtrent les tentatives d’exploitation de nos applications, tandis que d’autres vérifient si le code déployé est toujours sûr.

3.1. sanitize-filename

sanitize-filename (npmjs.com/sanitize-filename) nettoie une variable de tout caractère ambigu ou qui ne serait pas attendu.

sanitize-filename.js
'use strict';

const sanitize = require('sanitize-filename');

console.log(sanitize('aucun-problème.txt'));  // (1)
console.log(sanitize('../../.ssh/id_rsa'));   // (2)
  1. Affiche aucun-problème.txt.

  2. Affiche .....sshid_rsa – les caractères / sont nettoyés car il permettrait de créer des chemins compromettants pour l’application ou le système d’exploitation.

3.2. helmet

helmet (npmjs.com/helmet) est un module à intégrer systématiquement dans toute application Express. Il ajoute des en-têtes HTTP Content-Security Policy, Strict Transport Policy et d’autres qui empêchent le détournement d’informations.

Chacune de ses protections se configure aussi au cas par cas. Elles s’intègrent manuellement dans d’autres types d’applications web, y compris un serveur HTTP natif à Node.

3.3. dompurify

dompurify (npmjs.com/dompurify) nettoie un contenu HTML pour le rendre affichable en toute sécurité. Il nettoie des scripts indésirés, des balises mal formées qui casseraient l’affichage, ou encore des iframes qui injecteraient des contenus tiers sans notre consentement.

3.4. filenamify

filenamify (npmjs.com/filenamify) nettoie une valeur pour retirer tout caractère invalide dans un nom de fichier. C’est pratique pour laisser la possibilité à un utilisateur de choisir un nom de fichier sans pour autant mettre en danger le système ou l’application.

3.5. retire.js

retire.js (npmjs.com/retire) sert à scanner soi-même des vulnérabilités connues dans des fichiers JavaScript. Il est complémentaire de la commande npm audit car il inspecte des dépendances qui ne sont pas forcément sur npm.

3.6. snyk

snyk (npmjs.com/snyk) est à la fois un service en ligne et un module pour vérifier la présence de failles de sécurité connues dans les dépendances de nos projets.

4. Vérifier la syntaxe de notre code

La vérification syntaxique est un mécanisme s’assurant que votre code respecte la grammaire du langage associé. Elle révèle aussi des anomalies fondamentales (balise mal fermée, expression inconnue, etc.) et renforce des pratiques de programmation commune au groupe de développement.

Vérifier la syntaxe de notre code est une excellente première étape avant d’introduire des tests unitaires ou fonctionnels.

4.1. htmlhint

htmlhint (npmjs.com/htmlhint) vérifie la structure de nos documents HTML. Il rapporte les doublons d’attributs id, la présence de balises mal formées, l’absence de balise fermante ou encore l’existence de chaînes de caractères non imprimables dans des attributs critiques, entre autres.

Prenons en exemple le document suivant :

sample.html
<html>
<head>
  <link rel="stylesheet" href="sample.css">
</head>
<body>
  <button id="btn" class="btn btn-primary">OK</button>

  <button id="btn" class="btn">KO</button>
  
  <BUTTON class='btn__primary--curent btn--active'></BUTTON>
</body>
</html>

Une lecture distraite pourrait nous faire passer à côté d’erreurs et d’incohérences de programmation. Les erreurs de ce genre passent d’autant plus inaperçues que la base de code devient volumineuse et change fréquemment.

L’exécution de htmlhint avec ses règles par défaut remontera les alertes suivantes :

../node_modules/.bin/htmlhint sample.html
sample.html:
line 1, col 1: Doctype must be first.
line 8, col 10: Id redefinition of [ btn ].
line 10, col 3: Tagname [ BUTTON ] must be lower case.
...
line 10, col 52: Tagname [ BUTTON ] must be lower case.

4.2. eslint

eslint (npmjs.com/eslint) est l’outil de vérification syntaxique pour ECMAScript par excellence. Il est souple, rapide à mettre en œuvre et s’adapte à des contextes complexes. J’aime son mécanisme de configuration de règles : utilisation systématique du mode strict, nombre maximum de paramètres de fonctions, objets non déclarés, variables inconnues, etc.

eslint expose également des fonctions pour créer vos propres règles métier.

package.json
{
  "...": "...",
  "eslintConfig": {
    "env": {
      "node": true,
      "es6": true
    },
    "extends": [
      "eslint:recommended"
    ],
    "rules": {
      "strict": ["error", "global"],
      "quotes": ["error", "single"],
      "no-undef": "error",
      "curly": "error",
      "eqeqeq": "error"
    }
  }
}

Le niveau de sévérité de chaque règle est représenté par un identifiant :

  • none : règle désactivée ;

  • warn : affiche un avertissement ;

  • error : affiche une erreur (le processus se terminera avec un code d’erreur).

Certaines règles demandent ou acceptent des arguments supplémentaires. Elles sont toutes documentées sur le site web du projet : eslint.org/docs/rules/.

💬
Documentation Règles personnalisées

Un exemple réutilisable de règles personnalisées se trouve sur le dépôt GitHub de Airbnb :

4.3. csslint

csslint (npmjs.com/csslint) est un outil de vérification syntaxique de feuilles de style CSS. Il a été créé par deux anciens ingénieurs de Yahoo! dont les anciens travaux dans le domaine de la performance ont influencé l’architecture et le choix des règles par défaut.

csslint fournit les mécanismes de vérification adéquats pour alerter de possibles effets de bord de box model, de déclaration incompatible de @font-face, de vendor prefix dépréciés ou encore de combinaisons de propriétés connues pour casser l’affichage dans certains navigateurs.

Prenons par exemple le fichier CSS suivant :

sample.css
.btn {
  background: white;
  color: black;
  border: 0px solid black;
  height: 20px;
  padding: 10px;
}
.btn__primary {
  background-color: blue;
  color: white;
  font-size: 1.3em;
  transition: font-weight 0.2s ease;
}
.btn__primary--current {
  color: gray;
}
.btn__primary--current.btn--active {
  font-weight: 700;
}

csslint lancera trois alertes en lisant le fichier sample.css, même si celui-ci est syntaxiquement parfaitement valide :

../node_modules/.bin/csslint sample.css

csslint: There are 3 problems in sample.css.

sample.css
1: warning at line 4, col 11
Values of 0 shouldn't have units specified.
  border: 0px solid black;

sample.css
2: warning at line 4, col 3
Using height with border can sometimes make
  elements larger than you expect.
  border: 0px solid black;
...

4.4. doiuse

doiuse (npmjs.com/doiuse) est un utilitaire qui repose sur la base de données du site communautaire caniuse.com. Il nous alerte des possibles incompatibilités de syntaxe en fonction de la liste de navigateurs à gérer. Cette liste concerne aussi bien des versions spécifiques (Internet Explorer 8) que des parts de marché (tous les navigateurs avec plus de 5 % de parts de marché).

L’exemple suivant illustre les alertes relevées par doiuse dans le cas d’une recherche de compatibilité avec Internet Explorer 6 et Internet Explorer 7 :

../node_modules/.bin/doiuse -b 'ie < 8' sample.css
sample.css:1:1: CSS 2.1 selectors not supported by: IE (6)
sample.css:8:1: CSS 2.1 selectors not supported by: IE (6)
sample.css:12:1: CSS3 Transitions not supported by: IE (6,7)
sample.css:14:1: CSS 2.1 selectors not supported by: IE (6)

5. Optimiser notre code

Commentaires, indentations ou encore noms de variables : tout cela occupe de la place – autant d’octets transférés sur le réseau avant d’être exécutés par un client web. Les outils d’optimisation offrent l’opportunité aux développeurs et développeuses d’écrire du code sans compromettre sa lisibilité et sa maintenabilité.

Les minifieurs et optimiseurs mettent en œuvre différentes techniques pour réduire le poids de notre code :

  • suppression des commentaires et caractères non significatifs ;

  • renommage de variables ;

  • factorisation d’occurrences multiples similaires ;

  • suppression des instructions relatives au débogage/développement ;

  • suppression du code inutilisé ;

  • écriture automatique de code pour prendre en charge des environnements anciens ou futurs.

5.1. uglify-es

UglifyJS (npmjs.com/uglify-es) est un des premiers compresseurs à utiliser une représentation syntaxique en arbre (Abstract Syntax Tree – AST) en lieu et place des classiques optimisations avec expressions régulières.

Cette méthode élargit les perspectives de la compression via de la réécriture de code :

  • hoisting des variables (remontée de leur déclaration en début de portée) ;

  • combinaison des déclarations de variables ;

  • factorisation des valeurs de variables ;

  • réécriture partielle d’expressions ;

  • injection en ligne du contenu de variables.

UglifyJS s’utilise en ligne de commande ou comme un module Node.

5.2. postcss

PostCSS (npmjs.com/postcss) est une optimiseur CSS modulaire. Cet outil est construit autour d’un parseur CSS, d’un arbre syntaxique et d’un compilateur de texte. C’est la même recette qui a participé au succès et à la richesse fonctionnelle d’outils comme UglifyJS et ESLint.

Avec une ou plusieurs extension(s), vous basculez d’un optimiseur de code vers la possibilité de créer votre propre préprocesseur, comme Sass !

5.3. autoprefixer

autoprefixer (npmjs.com/autoprefixer) est le module qui vous épargnera l’écriture de centaines de lignes CSS. Il ajoute automatiquement les préfixes navigateurs aux bons endroits : -webkit, -moz, etc.

autoprefixer s’utilise comme extension au module PostCSS, en ligne de commande ou comme module Node.

../node_modules/.bin/postcss sample.css \
    --use autoprefixer  | grep transition
          transition: font-weight 0.2s ease;

Le choix de compatibilité avec les navigateurs repose sur la variable d’environnement BROWSERSLIST, gérée par le module browserslist (npmjs.com/browserslist) :

export BROWSERSLIST='firefox > 8'
../node_modules/.bin/postcss sample.css \
    --use autoprefixer | grep transition
     -moz-transition: font-weight 0.2s ease;
          transition: font-weight 0.2s ease;

5.4. uncss

uncss (npmjs.com/uncss) est le pendant inverse d'autoprefixer puisqu’il se charge de supprimer le code CSS inutilisé. Il s’utilise de manière autonome ou comme module PostCSS.

Le module charge une ou plusieurs page(s) web, calcule la différence entre les règles utilisées et celles qui ne le sont pas. Vous êtes libre de mentionner une liste blanche de règles à ne jamais supprimer.

5.5. csswring

csswring (npmjs.com/csswring) est un minifieur de code CSS qui s’interface lui aussi avec PostCSS. Vous lui donnez du code, il en ressort une version avec le minimum de caractères possible.

5.6. google-closure-compiler-js

Google Closure Compiler (npmjs.com/google-closure-compiler-js) est un compilateur ECMAScript plus poussé qu'UglifyJS mais qui impose un style d’écriture plus strict, voire plus contraignant. Ses optimisations sont en général bien plus poussées et permettent d’atteindre des niveaux de finesse difficiles à obtenir autrement.

5.7. csso

csso (npmjs.com/csso) est une alternative à csswring, écrite par l’équipe derrière la méthodologie BEM (en.bem.info).

csso ira jusqu’à réécrire les codes couleurs, les margin et padding et factorisera les sélecteurs similaires.

5.8. svgo

svgo (www.npmjs.com/svgo) s’attaque au nettoyage des fichiers graphiques vectoriels au format SVG. Il simplifie les chemins et supprime les attributs et déclarations superflues.

Vous pouvez l’essayer en ligne sur jakearchibald.github.io/svgomg/ ou l’intégrer comme extension à PostCSS.

5.9. wawoff2

wawoff2 (npmjs.com/wawoff2) optimise des polices de caractères pour le Web. Le module convertit des polices au format TTF vers le format WOFF2 – à préférer car plus léger et donc rapide à charger.

6. Passer d’un langage à un autre

Les préprocesseurs sont des outils de productivité pour CSS. Ils transforment un langage plus avancé dans quelque chose qui est compris par un navigateur web.

La même chose s’applique avec la compilation ou la transpilation pour ECMAScript, pour utiliser dès maintenant une version du futur.

6.1. less

less (npmjs.com/less) est un préprocesseur CSS. Il gère des variables, des mixins, des calculs de couleurs et des fonctions qui encouragent une écriture modulaire, plus logique et plus succincte.

stylesheet.less
@warning-color: red;
@base-font-size: 18px;

.btn {
  border: 1px solid black;
  border-radius: @base-font-size / 6;
  font-size: @base-font-size;

  &--large {
    font-size: @base-font-size * 1.5;
  }

  &--warning {
    border-color: fadeout(@warning-color, 10%);
    color: @warning-color;
  }
}

L’exécutable lessc compile le fichier less:

../node_modules/.bin/lessc stylesheet.less

6.2. sass

sass (npmjs.com/node-sass) est un autre préprocesseur CSS. Il est issu du monde Ruby et est désormais tout aussi puissant dans Node grâce à LibSass, un module rapide et portable écrit en C++.

6.3. browserify

browserify (npmjs.com/browserify) transforme des modules et du code initialement écrit pour Node vers du code exécutable dans un navigateur web.

Un puissant mécanisme de transformations étend ses capacités au coup par coup.

💬

Nous en parlons plus en détail dans la section “Importer des modules npm pour le Web” au chapitre 9.

6.4. babel

babel (npmjs.com/babel) est un outil qui permet de passer d’une version d’ECMAScript à une autre, fonctionnalité par fonctionnalité. C’est un outil indispensable pour écrire un code moderne et le faire fonctionner dans des navigateurs anciens.

6.5. typescript

TypeScript (npmjs.com/typescript) est un langage de programmation typé. Toute structure utilisée est décrite avec un schéma que TypeScript valide. Nous sommes prévenu·e·s des erreurs avant même d’avoir exécuté notre code car l’outillage sait si on manipule des données qui existent.

Au final, le code est transformé en ECMAScript et exécuté en tant que tel. Le code est tellement propre que nous pouvons arrêter d’utiliser TypeScript du jour au lendemain et travailler sur le code qu’il aura généré sans aucun problème.

7. Gérer des fichiers

Ces bibliothèques nous aident à écrire moins de lignes de code pour des besoins quotidiens de manipulation de fichiers.

7.1. mkdirp

mkdirp (npmjs.com/mkdirp) est identique à la commande Unix mkdir -p, c’est-à-dire que les répertoires seront créés récursivement s’ils n’existent pas au préalable.

Si nous utilisions le module Node fs, nous devrions créer l’arborescence de répertoires par nous-même, niveau par niveau.

7.2. rimraf

rimraf (npmjs.com/rimraf) est le pendant opposé de mkdirp. Il supprime une arborescence de manière récursive. C’est l’équivalent de la commande Unix rm -rf.

Si nous utilisions le module Node fs, nous devrions supprimer d’abord les fichiers puis les répertoires, un par un.

7.3. glob

glob (npmjs.com/glob) est un utilitaire pour obtenir une liste de fichiers en utilisant des motifs.

glob.js
'use strict';

const {promisify} = require('util');
const glob = promisify(require('glob'));

glob('*.js').then(console.log);     // (1)
glob('re*.js').then(console.log);   // (2)
glob('sample.*').then(console.log); // (3)
  1. Affiche une liste de fichiers dont l’extension est .js.

  2. Affiche une liste de fichiers qui commencent par re et dont l’extension est .js.

  3. Affiche une liste de fichiers qui s’appellent sample, peu importe leur extension.

7.4. fs-extra

fs-extra (npmjs.com/fs-extra) est une collection de fonctions pour gérer les opérations de fichiers. Le module inclut rimraf et mkdirp en plus d’autres fonctions récursives, pour copier, déplacer ou supprimer des fichiers.

7.5. graceful-fs

graceful-fs (npmjs.com/graceful-fs) est identique au module Node fs.

La différence se situe sous le capot : le module gère les défaillances du système et tente d’accéder à nouveau aux ressources demandées si les erreurs sont liées à des problèmes de performance.

C’est un module à utiliser si notre application dépend fortement de la disponibilité du système de fichiers et si celui-ci est fortement sollicité.

7.6. chokidar

chokidar (npmjs.com/chokidar) crée des observateurs du système de fichiers. Il gère les différences des systèmes d’exploitation et nous permet d’écrire un seul et même code.

C’est la bibliothèque vers laquelle se tourner lorsque nous avons besoin de déclencher des actions quand des fichiers sont modifiés.

8. Stocker dans des bases de données

Node sait communiquer avec tout type de bases de données grâce à l’écosystème npm. Préférez les modules faisant état de pilote natif/binaire – le transfert de données n’en sera que plus rapide.

8.1. db-migrate

db-migrate (npmjs.com/db-migrate) est un outil de gestion de migrations pour MySQL, SQLite, MongoDB et PostgreSQL. À l’aide de scripts de migration, il rend reproductibles des changements de structure dans une base de données – ajout ou suppression de champ, de table ou d’index.

8.2. knex

knex (npmjs.com/knex) propose d’interagir et d’interroger des bases de données SQL comme PostgreSQL, MariaDB, MySQL et SQLite.

Les requêtes s’écrivent en SQL pur ou en utilisant une API dite “fluide”, pour ne pas écrire le SQL à la main.

knex.js
'use strict';

const {join} = require('path');

const db = require('knex')({
  client: 'sqlite3',                            // (1)
  connection: {
    filename: join(__dirname, 'sample.sqlite')  // (2)
  }
});

Promise.all([
  db('books').where('title', 'like', '%Node%'), // (3)
  db('books').count('title as count').first(),  // (4)
])
.then(([rows, count]) => {
  console.log(rows);                            // (5)
  console.log(count);                           // (6)
  db.destroy();
});
  1. Indique que nous allons nous connecter à une base de données de type SQLite.

  2. Spécifie l’emplacement de la base de données.

  3. Effectue une recherche floue sur les lignes dont le titre contient le mot 'Node'.

  4. Compte le nombre de lignes et retourne le premier (et seul) résultat de la requête.

  5. Affiche [ { id: 1, title: 'Node.js ', created_at: '2018-07-11 10:34:33' } ].

  6. Affiche { count: 3 }.

8.3. bookshelf

bookshelf (npmjs.com/bookshelf) est une surcouche à Knex, écrite par les mêmes personnes. Elle modélise les données sous forme d’objets et de schémas (ORM) pour automatiser des actions et ajouter plus d'“intelligence” à notre modèle de données.

8.4. sequelize

sequelize (npmjs.com/sequelize) est une alternative à Knex et à Bookshelf. Elle gère des schémas de données de manière optionnelle, mais aussi les migrations. Ces dernières permettent de scripter les changements de structure d’une base de données, de les tester en local avant de les jouer en production.

8.5. mongoose

mongoose (npmjs.com/mongoose) sert à composer des modèles de données pour la base de données MongoDB – dite NoSQL. Elle définit des comportements annexes comme des mixins ou des accesseurs dynamiques.

8.6. levelup

LevelDB (npmjs.com/levelup) est un système de bases de données clé/valeur extrêmement modulaire. Le stockage se fait sur disque par défaut, mais il peut évoluer vers du stockage en mémoire (module memdown) ou même dans un navigateur web (avec IndexedDB).

levelup.js
'use strict';

const levelup = require('levelup');
const memdown = require('memdown');
const encode = require('encoding-down');

const db = levelup(encode(memdown(),          // (1)
  { valueEncoding: 'json' }
));

Promise.all([
  db.put('node', {title: 'Node.js'}),
  db.put('css', {title: 'CSS maintenables'}),
  db.put('opensky', {title: 'Open Sky'}),
])
.then(() => db.get('node'))                   // (2)
.then(result => {
  console.log(result);                        // (3)
});
  1. Crée la connexion à la base de données en mémoire.

  2. Recherche un enregistrement après l’avoir enregistré en mémoire.

  3. Affiche { title: 'Node.js' }.

8.7. redis

redis (npmjs.com/redis) est un gestionnaire de bases de données clés/valeurs distribuées et performantes.

redis.js
'use strict';

const client = require('redis').createClient();
const hset = require('util').promisify(client.hset);

Promise.all([
  hset('book:node', 'title', 'Node.js'),
  hset('book:css', 'title', 'CSS maintenables'),
  hset('book:opensky', 'title', 'Open Sky')
])
.then(() => {
  console.log('Enregistrements créés.');
  client.end();
});

hiredis (npmjs.com/hiredis) est un pilote C++ qui augmente les performances de connexion à une base de données redis.

8.8. elasticsearch

elasticsearch (npmjs.com/elasticsearch) est un client pour simplifier la connexion à une base de données Elasticsearch. Une base de ce type est particulièrement adaptée à l’indexation des données, pour des recherches performantes et complexes.

9. Ligne de commande

Ces modules complètent le panorama déjà très varié présenté dans le chapitre 8.

9.1. yargs-parser

yargs-parser (npmjs.com/yargs-parser) est le module d’interprétation des arguments utilisé par le module yargs. C’est une alternative plus puissante et plus complexe que minimist.

9.2. args

args (npmjs.com/args) est un module minimaliste pour interpréter les arguments, les structurer et afficher une aide claire à nos utilisateurs et utilisatrices.

Cerise sur le gâteau : le module suggère un choix de commande en cas d’erreur de frappe.

9.3. caporal

caporal (npmjs.com/caporal) est un framework complet pour bâtir des applications en ligne de commandes. Il gère les classiques arguments et options ainsi que les sous-commandes, les types de valeurs et l’autocomplétion.

9.4. promptly

promptly (npmjs.com/promptly) est un utilitaire pour poser des questions, valider et travailler avec les réponses obtenues. Il est minimaliste et a un faible nombre de dépendances.

9.5. supports-color

supports-color (npmjs.com/supports-color) vérifie si le contexte d’exécution du programme en ligne de commande supporte les couleurs.

Cela nous évite d’envoyer des codes ANSI, qui, seraient affichés au lieu d’être interprétés comme des couleurs.

10. Applications web

Ces modules complètent le panorama déjà très varié présenté dans le chapitre 7.

10.1. fastify

fastify (npmjs.com/fastify) est un framework inspiré de Express. Il se focalise sur la simplicité de l’expérience de développement et sur de hautes performances. Il sait valider les données sortantes à l’aide de schémas.

Pour aller au-delà des données, il se combine avec le module point-of-view (npmjs.com/point-of-view). Vous avez ainsi accès à l’utilisation de modules de templating.

10.2. passport

passport (npmjs.com/passport) est une bibliothèque modulaire d’authentification pour Express. Elle se branche à différents mécanismes pour vérifier les utilisateurs : utilisateur et mot de passe, compte GitHub, Twitter, OAuth, etc.

Les sessions d’utilisateurs se gèrent à côté – pour mémoriser qui est connecté ou non, et avec quel identifiant sécurisé et unique.

Référez-vous à sa documentation pour des exemples détaillés d’utilisation.

10.3. restify

restify (npmjs.com/restify) est un framework web spécialisé dans la création d’API HTTP.

Il gère les versions de routes et expose un client permettant de consommer des données sur d’autres API REST – proxy.

restify.js
'use strict';

const restify = require('restify');
const {NotFoundError} = require('restify-errors');
const server = restify.createServer();
const countries = require('i18n-iso-countries');

const responseV1 = (request, response, next) => {
  const codes = countries.getNames('en');

  if (codes[request.params.code] === undefined) {
    return next(new NotFoundError('Country not found'));
  }

  response.send(200, codes[request.params.code]);

  next();
};

server.get({ path: '/:code', version: '1.0.0' }, responseV1);
server.listen(8080, () => {
  console.log('Serveur accessible sur %s', server.url);
});

10.4. faye

faye (npmjs.com/faye) est un serveur WebSocket pour communiquer en temps réel entre un client et un serveur. Il sait débrayer vers Ajax ou JSON-P pour les navigateurs anciens qui ne comprennent pas WebSocket.

faye.js
'use strict';

const http = require('http');
const faye = require('faye');

const ws = new faye.NodeAdapter({
  mount: '/realtime', timeout: 10
});

const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Tyoe': 'text/plain' });
  res.end('Contenu non temps réel');
});

ws.attach(server);
server.listen(3000);

Cet exemple de serveur minimaliste expose un point d’entrée auquel on peut accéder via le client Faye, dans un navigateur ou via un autre script Node.

Tout message émit par un client sera relayé auprès des autres clients connectés.

10.5. swagger-client

swagger-client (npmjs.com/swagger-client) sert à valider des requêtes et des réponses HTTP en fonction de schémas qui répondent à la spécification OpenAPI.

Cette spécification permet entre autres de gérer automatiquement les routes de notre application pour nous concentrer sur le code qui génère les données de sortie.

11. Modules front-end et templating

Les bibliothèques de templating proposent d’associer une structure de données à une logique de présentation. Pour la plupart, elles fonctionnent aussi bien sous Node que dans les navigateurs, ce qui est une excellente nouvelle pour partager des comportements d’affichage entre les deux environnements.

Tous les modules que nous allons voir généreront cette sortie HTML :

<!DOCTYPE html>
<html>
<head>
  <title>Template demo</title>
</head>
<body>
  <ul>
    <li>CSS maintenables</li>
    <li>Node.js</li>
    <li>Open Sky</li>
  </ul>
</body>
</html>

11.1. nunjucks

nunjucks (npmjs.com/nunjucks) est un portage de Jinja, bibliothèque bien connue par les adeptes de Python. Sa syntaxe inclut des fonctionnalités comme les filtres, les blocs ou l’héritage de gabarit.

template.html
<!DOCTYPE html>
<html>
<head>
  <title>{{ title | default('Template demo') | capitalize }}</title>
</head>
<body>
{% set items = ['Node.js', 'CSS maintenables', 'Open Sky'] -%}
<ul>
{% for item in items|sort -%}
  <li>{{ item }}</li>
{% endfor -%}
</ul>
</body>
</html>

11.2. handlebars

handlebars (npmjs.com/handlebars) et son prédécesseur mustache sont les vétérans du templating Node. Leur parti pris est de proposer le minimum de logique afin que celle-ci reste au plus près des données.

handlebars sait aussi précompiler les gabarits sous forme de fonctions ECMAScript.

template.hbs
<!DOCTYPE html>
<html>
<head>
  <title>{{#if title}}{{title}}{{else}}Template demo{{/if}}</title>
</head>
<body>
<ul>
  {{#each items}}
  <li>{{.}}</li>
  {{/each}}
</ul>
</body>
</html>

11.3. pug

pug (npmjs.com/pug) opte pour un parti minimaliste qui repose entièrement sur l’indentation. Son mécanisme de blocs facilite la réutilisation d’éléments de présentation.

template.pug
doctype html
html
  head
    title= title || 'Template demo'
  body
    ul
      each item in ['Node.js', 'CSS maintenables', 'Open Sky']
        li= item

11.4. ejs

ejs (npmjs.com/ejs) part du principe qu’il n’y a pas besoin d’un langage de templating autre qu’ECMAScript. Donc c’est tout simplement ce qui vous sera proposé, impliquant de ce fait une faible courbe d’apprentissage.

template.ejs
<!DOCTYPE html>
<html>
<head>
  <title><%= typeof title === 'string' ? title : 'Template demo' %></title>
</head>
<body>
<ul>
  <% ['Node.js', 'CSS maintenables', 'Open Sky'].forEach((item) => { -%>
  <li><%= item %></li>
  <% }); -%>
</ul>
</body>
</html>

11.5. react

React (npmjs.com/react) est une bibliothèque de présentation dite “réactive” et orientée composants. Elle génère un arbre visuel à partir de données passées en entrée. Cet arbre est ensuite transformé en HTML, en interface iOS ou Android, entre autres.

template.jsx
'use strict';

const React = require('react');

const BookList = ({books=[]}) => {
  return (<ul>
    {books.map((bookName, i) => (
      <li key={i}>{bookName}</li>
    ))}
  </ul>);
}

module.exports = ({title, books}) => {
  return (
    <html>
      <head>
        <title>{title || 'Template demo'}</title>
      </head>
      <body>
        <BookList books={books} />
      </body>
    </html>
  );
};

11.6. storybook

storybook (github.com/storybooks/storybook) complète React et d’autres frameworks de templating en créant un catalogue de composants auto-documentés. Les composants sont affichés en même temps que le code nécessaire pour les utiliser dans une autre application.

12. Tester notre code

Le module assert intégré à Node suffit pour démarrer. Il existe cependant tout un outillage pour tester notre code à destination de Node (tests unitaires) ou des navigateurs (tests fonctionnels) ainsi que pour écrire des assertions plus facilement.

12.1. tape

tape (npmjs.com/tape) est une bibliothèque d’exécution de tests minimaliste qui se base sur le Test Anything Protocol (TAP, testanything.org). Elle embarque aussi le minimum vital pour écrire des assertions.

tape.js
'use strict';

const test = require('tape');

test('Date test', (t) => {                             // (1)
  t.plan(1);

  t.ok(Date.now() > new Date('2013-03-24').getTime()); // (2)
});
  1. Création d’un test.

  2. Écriture d’une assertion.

12.2. chai

chai (npmjs.com/chai) est une bibliothèque poussée d’assertions. Son mécanisme chaîne permet de quasiment écrire des phrases pour exprimer l’intention des choses à vérifier.

chai.js
'use strict';

const {expect} = require('chai');

expect([1, 2]).to.be.an('array');             // (1)
expect([1, 2]).to.deep.equal([1, 2]);         // (2)
expect({}).to.be.an('object').and.to.be.empty;// (3)
  1. Vérification du type d’une variable.

  2. Vérification stricte de valeur d’une variable.

  3. Double vérification – il s’agit bien d’objet et il est vide, sans clé/valeur.

12.3. sinon

sinon (npmjs.com/sinon) est un compagnon idéal pour intercepter le fonctionnement interne de variables et d’objets. Le module propose de créer des écouteurs (spys) et des bouchons (stubs, mocks).

En d’autres termes, vous prenez la main sur des portions de votre propre code pendant la durée des tests. Ces techniques servent pour simuler des erreurs et différentes situations tout en observant le comportement réel de notre code.

sinon.js
'use strict';

const test = require('tape');
const sinon = require('sinon');

test('Date', (t) => {
  const d = Date;
  const dateTime = new Date('1983-03-24').getTime();
  const stub = sinon.stub(d, 'now');    // (1)
  stub.returns(9999999999999);          // (2)

  d.now();
  t.equal(stub.calledOnce, true);       // (3)
  t.ok(stub.returnValues[0] > dateTime);
  t.end();
});
  1. Création d’un bouchon pour la méthode now() d’un objet Date.

  2. Surcharge de la valeur retournée par la méthode d.now().

  3. Nous constatons le nombre de fois où la méthode d.now() a été appelée.

Le module sinon-chai (npmjs.com/sinon-chai) intègre sinon avec le mécanisme d’assertions de chai.

12.4. nyc

nyc (npmjs.com/nyc) génère une couverture de code. Il inspecte le code exécuté pendant les tests et en déduit les portions qui n’ont pas été visitées et, donc, qui n’ont pas été testées. C’est un indicateur utile pour attester de la fiabilité d’une base de code – plus la couverture est importante, plus il y a de chances que les cas à la marge aient été vérifiés.

nyc cli
Figure 1. Couverture de code visualisée dans un terminal

nyc se greffe sur n’importe quelle bibliothèque d’exécution de tests. Sous le capot, c’est le module istanbul (npmjs.com/istanbul) qui est utilisé pour effectuer les calculs de couverture de code.

nyc web
Figure 2. Couverture de code visualisée dans un navigateur web

12.5. karma

karma (npmjs.com/karma) pilote l’exécution de tests depuis un ou plusieur(s) navigateurs web. Ces derniers (Chrome, Safari, Firefox, etc.) se pilotent sur notre ordinateur, depuis une machine virtuelle (VirtualBox) ou même par le biais d’un service en ligne (SauceLabs, BrowserStack, etc.).

karma
Figure 3. Exemple d’exécution de tests en continu avec Karma

12.6. supertest

supertest (npmjs.com/supertest) sert à tester une interface HTTP. Le module envoie des requêtes et nos assertions vérifient qu’elles retournent bien ce qui est attendu – code HTTP, structure de réponse etc.

Je trouve ce module pratique pour tester des choses qui seraient difficiles à couvrir uniquement avec des tests unitaires.

13. Objets connectés

Node a bénéficié de l’engouement autour des objets connectés grâce à sa nature asynchrone et à sa légèreté. C’est une plate-forme de choix pour dialoguer ou embarquer dans des nano-ordinateurs, réfrigérateurs et autres ampoules connectées.

13.1. nitrogen

nitrogen (npmjs.com/nitrogen) gère les interactions entre différents périphériques, sur un même réseau local et à travers Internet.

La bibliothèque se base sur un mécanisme déclaratif de fonctionnalités et de terminaux ainsi que la publication de messages.

13.2. serialport

serialport (npmjs.com/serialport) est la bibliothèque de base pour communiquer avec le port série d’un appareil. Un câble USB suffit ensuite pour envoyer nos instructions à cet appareil.

13.3. firmata

firmata (npmjs.com/firmata) est un firmware, un protocole de communication, ainsi qu’une bibliothèque de communication pour microcontrôleur Arduino.

Le module Node apprend ainsi à communiquer avec un Arduino préalablement flashé avec Firmata. Cela nous permet notamment d’écrire des applications en JavaScript au lieu d’utiliser du C.

13.4. johnny-five

johnny-five (npmjs.com/johnny-five) est une bibliothèque haut niveau pour Arduino, Raspberry Pi et tout autre microcontrôleur. Elle simplifie les interactions avec des moteurs, des servo-contrôleurs, des capteurs etc.

13.5. node-red

node-red (npmjs.com/node-red) est une interface visuelle pour programmer des flux de données entre objets connectés. Le projet émane d’employé·e·s d’IBM.

L’exécutable démarre un serveur web dont l’interface nous sert à relier des sources de données, des réactions à des événements avec des objets prêts à recevoir les instructions.

14. Accessibilité

L’écosystème npm a participé à un essor d’outillage lié à l’accessibilité d’applications web. Auparavant, les outils étaient difficilement automatisables.

14.1. a11y

a11y (npmjs.com/a11y) est un automate d’inspection de pages web. Il détecte des problèmes de contrastes, de calques qui masquent du contenu ou d’éléments qui ne seraient pas navigables au clavier, entre autres.

C’est un excellent outil pour améliorer la qualité d’une application tout en l’ouvrant à un public trop souvent mis de côté.

npx a11y https://thom4.net
  ✖ Controls and media elements should have labels

  #search > .form-control


✔ This element does not support ARIA roles
✔ Elements with ARIA roles must be in the correct scope
✔ This element has an invalid ARIA attribute
✔ ARIA state and property values must be valid

14.2. a11y.css

a11y.css (npmjs.com/a11y.css) est une feuille de styles CSS à injecter dans une page web pour rendre visible des incohérences. Parmi ces dernières, nous retrouvons des boutons sans intitulé, l’absence de langue du document ou encore l’absence de bouton de validation de formulaire ou de texte alternatif d’images.

14.3. lighthouse

lighthouse (npmjs.com/lighthouse) est l’outil d’analyse de performances, de référencement (SEO) et d’accessibilité embarqué dans le navigateur web Google Chrome.

Ce module npm le rend utilisable depuis un terminal et écrit le rapport dans un fichier HTML.

14.4. storybook-addon-a11y

storybook-addon-a11y (npmjs.com/storybook-addon-a11y) est une extension au module storybook. Le module signale les problèmes d’accessibilité au niveau de chaque composant. Le suivi est ainsi fait en continu, au plus proche des composants distribués et utilisés dans les applications.

15. Travailler avec des images, des sons et des vidéos

15.1. sharp

sharp (npmjs.com/sharp) est un module de redimensionnement et de transformation d’images JPG, PNG et WebP écrit en JavaScript et C++. Il ne nécessite pas de programme externe et est compatible avec une approche en flux.