Node.js est un moteur d’exécution JavaScript basé sur le même moteur V8 que celui utilisé dans le navigateur Chrome de Google. Il est souvent utilisé pour créer des applications multi_plateformes côté serveur et terminal. Node.js est devenu de plus en plus populaire au cours de la dernière décennie parce qu’il est facile à installer, pratique à utiliser, rapide et qu’il permet aux développeurs web côté client de mettre à profit leurs compétences ailleurs.

Cependant, le développement de logiciels reste une tâche complexe, et votre code Node.js échouera à un moment donné. Ce tutoriel présente divers outils pour aider à déboguer les applications et trouver la cause d’un problème.

Plongeons-y.

Consultez notre guide vidéo sur le débogage du code Node.js

Vue globale du débogage

« Débogage » est le nom donné aux différents moyens de corriger les défauts des logiciels. La correction d’un bogue est souvent simple. Trouver la cause du bogue peut être considérablement plus complexe et entraîner de nombreuses heures de réflexion.

Les sections suivantes décrivent trois types généraux d’erreurs que vous rencontrerez.

Erreurs de syntaxe

Votre code ne respecte pas les règles du langage – par exemple, lorsque vous omettez un crochet fermant ou que vous écrivez mal une instruction telle que console.lag(x).

Un bon éditeur de code peut vous aider à repérer les problèmes courants :

  • Code couleur pour les déclarations valides ou non valides
  • Vérification du type des variables
  • Complétion automatique des noms de fonctions et de variables
  • Mise en évidence des parenthèses correspondantes
  • Mise en retrait automatique des blocs de code
  • Détection du code inaccessible
  • Refactorisation des fonctions désordonnées

Les éditeurs gratuits tels que VS Code et Atom offrent un excellent support pour Node.js, JavaScript et TypeScript (qui se transpose en JavaScript). Les problèmes de syntaxe de base peuvent généralement être repérés avant que vous n’enregistriez et ne testiez votre code.

Un linter de code comme ESLint signalera également les erreurs de syntaxe, les mauvaises indentations et les variables non déclarées. ESLint est un outil Node.js que vous pouvez installer globalement avec :

npm i eslint -g

Vous pouvez vérifier les fichiers JavaScript à partir de la ligne de commande en utilisant :

eslint mycode.js

…mais il est plus facile d’utiliser une extension d’éditeur tel que ESLint pour VS Code ou linter-eslint pour Atom, qui valide automatiquement le code au fur et à mesure que vous le saisissez :

ESlint dans VS Code.
ESlint dans VS Code.

Erreurs de logique

Votre code s’exécute mais ne fonctionne pas comme vous l’attendez. Par exemple, un utilisateur n’est pas déconnecté lorsqu’il le demande ; un rapport affiche des chiffres incorrects ; les données ne sont pas entièrement enregistrées dans une base de données ; etc.

Les erreurs logiques peuvent être causées par :

  • Une utilisation de la mauvaise variable
  • Des conditions incorrectes, par exemple if (a > 5) plutôt que if (a < 5)
  • Des calculs qui ne tiennent pas compte de la précédence des opérateurs, par exemple 1+2*3 donne 7 au lieu de 9.

Erreurs de moteur d’exécution (ou d’exécution)

Une erreur ne devient évidente que lorsque l’application est exécutée, ce qui conduit souvent à un crash. Les erreurs d’exécution peuvent être causées par :

  • Diviser par une variable qui a été mise à zéro
  • Tenter d’accéder à un élément de tableau qui n’existe pas
  • Tenter d’écrire dans un fichier en lecture seule

Les erreurs de logique et d’exécution sont plus difficiles à repérer, bien que les techniques de développement suivantes puissent aider :

  1. Utilisez le développement piloté par les tests : Le TTD ou Test-Driven Development vous encourage à écrire des tests avant le développement d’une fonction, par exemple : X est renvoyé par la fonctionY lorsque Z est passé en paramètre. Ces tests sont exécutés lors du développement initial et des mises à jour ultérieures pour s’assurer que le code continue à fonctionner comme prévu.
  2. Utilisez un système de suivi des problèmes : Il n’y a rien de pire qu’un e-mail affirmant « Votre logiciel ne fonctionne pas ! » Les systèmes de suivi des problèmes vous permettent d’enregistrer des problèmes spécifiques, de documenter les étapes de reproduction, de déterminer les priorités, d’affecter des développeurs et de suivre la progression des corrections.
  3. Utilisez le contrôle des sources : Un système de contrôle de la source tel que Git vous aidera à sauvegarder le code, à gérer les révisions et à identifier l’endroit où un bogue a été introduit. Les dépôts en ligne, notamment Github et Bitbucket, offrent un espace et des outils gratuits pour les projets de petite taille ou à code open source.

Vous rencontrerez toujours des bogues de Node.js, mais les sections suivantes décrivent les moyens de localiser cette erreur insaisissable.

Définissez les variables d’environnement Node.js appropriées

Les variables d’environnement définies dans le système d’exploitation hôte peuvent contrôler les réglages des applications et des modules Node.js. La plus courante est NODE_ENV, qui est généralement définie sur le développement lors du débogage ou sur la production lors de l’exécution sur un serveur en direct. Configurez les variables d’environnement sur macOS ou Linux avec la commande :

NODE_ENV=development

ou avec l’invite de commande (classique) de Windows :

set NODE_ENV=development

ou Windows Powershell :

$env:NODE_ENV="development"

Dans le célèbre framework Express.js, le fait de définir NODE_ENV sur le développement désactive la mise en cache des fichiers de modèle et produit des messages d’erreur verbeux, ce qui peut être utile lors du débogage. D’autres modules peuvent offrir des fonctionnalités similaires, et vous pouvez ajouter une condition NODE_ENV à vos applications, par exemple.

// running in development mode?
const devMode = (process.env.NODE_ENV !== 'production');

if (devMode) {
  console.log('application is running in development mode');
}

Vous pouvez également utiliser la méthode util.debuglog de Node pour émettre des messages d’erreur de manière conditionnelle, par exemple.

import { debuglog } from 'util';
const myappDebug = debuglog('myapp');
myappDebug('log something');

Cette application ne produira le message de journal que lorsque NODE_DEBUG est défini sur myapp ou un caractère générique tel que * ou my*.

Utiliser les options de ligne de commande de Node.js

Les scripts Node sont généralement lancés avec node suivi du nom du script d’entrée :

node app.js

Vous pouvez également définir des options de ligne de commande pour contrôler divers aspects de l’exécution. Les signalements (flags) utiles pour le débogage incluent :

  • --check
    vérifier la syntaxe du script sans l’exécuter
  • --trace-warnings
    produire une trace de pile lorsque les Promesses JavaScript ne sont pas résolues ou rejetées
  • --enable-source-maps
    afficher les cartes sources lors de l’utilisation d’un transpilateur tel que TypeScript
  • --throw-deprecation
    avertir lorsque des fonctionnalités dépréciées de Node.js sont utilisées
  • --redirect-warnings=file
    sortir des avertissements dans un fichier plutôt que sur stderr
  • --trace-exit
    afficher une trace de la pile lorsque process.exit() est appelé.

Sortir des messages sur la console

La sortie d’un message dans la console est l’une des façons les plus simples de déboguer une application Node.js :

console.log(`someVariable: ${ someVariable }`);

Peu de développeurs réalisent qu’il existe de nombreuses autres méthodes de console :

Méthode Console Description
.log(msg) message standard de la console
.log('%j', obj) sortie de l’objet sous forme de chaîne JSON compacte
.dir(obj, opt) impression des propriétés de l’objet
.table(obj) sortie des tableaux et des objets sous forme de tableau
.error(msg) un message d’erreur
.count(label) incrémenter un compteur nommé et le sortir
.countReset(label) réinitialisation d’un compteur nommé
.group(label) indenter un groupe de messages
.groupEnd(label) terminer un groupe
.time(label) démarrer une minuterie nommée
.timeLog(label) rapporter le temps écoulé
.timeEnd(label) arrêter une minuterie nommée
.trace() afficher une trace de la pile (une liste de tous les appels de fonction effectués)
.clear() effacer la console

console.log() accepte également une liste de valeurs séparées par des virgules :

let x = 123;
console.log('x:', x);
// x: 123

…bien que la déstructuration ES6 offre un résultat similaire avec moins d’efforts :

console.log({ x });
// { x: 123 }

La commande console.dir() imprime les propriétés des objets de la même manière que util.inspect():

console.dir(myObject, { depth: null, color: true });

Controverse sur la console

Certains développeurs prétendent que vous ne devriez jamais utiliser console.log() car :

  • Vous modifiez le code et pouvez altérer quelque chose ou oublier de le supprimer, et
  • Ce n’est pas nécessaire quand il existe de meilleures options de débogage.

Ne croyez pas ceux qui prétendent ne jamais utiliser console.log()! La journalisation est rapide et sale, mais tout le monde l’utilise à un moment ou à un autre. Utilisez l’outil ou la technique que vous préférez. La correction d’un bogue est plus importante que la méthode que vous adoptez pour le trouver.

Utilisez un système de journalisation tiers

Les systèmes de journalisation tiers offrent des fonctionnalités plus sophistiquées telles que les niveaux de messagerie, la verbosité, le tri, la sortie de fichiers, le profilage, les rapports, etc. Les solutions les plus populaires sont cabin, loglevel, morgan, pino, signale, storyboard, tracer et winston.

Utilisez l’inspecteur V8

Le moteur JavaScript V8 fournit un client de débogage que vous pouvez utiliser dans Node.js. Démarrez une application en utilisant node inspect, par exemple

node inspect app.js

Le débogueur s’arrête à la première ligne et affiche une invite debug> :

$ node inspect .\mycode.js
< Debugger listening on ws://127.0.0.1:9229/143e23fb
< For help, see: https://nodejs.org/en/docs/inspector
<
 ok
< Debugger attached.
<
Break on start in mycode.js:1
> 1 const count = 10;
  2
  3 for (i = 0; i < counter; i++) {
debug>

Saisissez help pour afficher une liste de commandes. Vous pouvez avancer dans l’application en entrant :

  • cont ou c : continuer l’exécution
  • next ou n : exécuter la commande suivante
  • step ou s : entrer dans une fonction en cours d’appel
  • out ou o : sortir d’une fonction et revenir à l’instruction appelante
  • pause : interrompt l’exécution du code
  • watch(‘myvar’) : surveille une variable
  • setBreakPoint() ou sb() : définit un point d’arrêt
  • restart : redémarre le script
  • .exit ou Ctrl | Cmd + D : quitte le débogueur

Il faut admettre que cette option de débogage est longue et peu maniable. Ne l’utilisez que lorsqu’il n’y a pas d’autre option, comme lorsque vous exécutez du code sur un serveur distant et que vous ne pouvez pas vous connecter depuis un autre endroit ou installer un logiciel supplémentaire.

Utilisez le navigateur Chrome pour déboguer le code Node.js

L’option d’inspection de Node.js utilisée ci-dessus démarre un serveur Web Socket qui écoute sur le port 9229 de localhost. Elle lance également un client de débogage en mode texte, mais il est possible d’utiliser des clients graphiques, tels que celui intégré à Google Chrome et aux navigateurs basés sur Chrome comme Chromium, Edge, Opera, Vivaldi et Brave.

Pour déboguer une application web typique, lancez-la avec l’option –inspect pour activer le serveur Web Socket du débogueur V8 :

node --inspect index.js

Note :

  • index.js est présumé être le script d’entrée de l’application.
  • Veillez à utiliser --inspect avec des doubles tirets pour vous assurer que vous ne démarrez pas le client du débogueur en mode texte.
  • Vous pouvez utiliser nodemon au lieu de node si vous souhaitez redémarrer automatiquement l’application lorsqu’un fichier est modifié.

Par défaut, le débogueur n’accepte que les connexions entrantes provenant de la machine locale. Si vous exécutez l’application sur un autre appareil, une machine virtuelle ou un conteneur Docker, utilisez :

node --inspect=0.0.0.0:9229 index.js
Option d'inspection de node.
Option d’inspection de node.

Vous pouvez également utiliser --inspect-brk au lieu de --inspect pour arrêter le traitement (définir un point de terminaison) sur la première ligne afin de pouvoir parcourir le code depuis le début.

Ouvrez un navigateur basé sur Chrome et saisissez chrome://inspect dans la barre d’adresse pour afficher les périphériques locaux et en réseau :

Outil d'inspection de Chrome.
Outil d’inspection de Chrome.

Si votre application Node.js n’apparaît pas comme une cible distante, soit :

  • Cliquez sur Ouvrir DevTools dédié à Node et choisissez l’adresse et le port, ou bien
  • Cochez Découvrir les cibles réseau, cliquez sur Configurer, puis ajoutez l’adresse IP et le port du périphérique sur lequel il s’exécute.

Cliquez sur le lien inspecter de la cible pour lancer le client de débogage DevTools. Cela devrait être familier à toute personne ayant utilisé DevTools pour le débogage de code côté client :

Chrome DevTools.
Chrome DevTools.

Passez au panneau des sources. Vous pouvez ouvrir n’importe quel fichier en appuyant sur Cmd | Ctrl + P et en saisissant son nom de fichier (tel que index.js).

Cependant, il est plus facile d’ajouter le dossier de votre projet à l’espace de travail. Cela vous permet de charger, de modifier et d’enregistrer des fichiers directement à partir de DevTools (que vous pensiez que c’est une bonne idée ou non est une autre question !)

  1. Cliquez sur + Ajouter un dossier à l’espace de travail
  2. Sélectionnez l’emplacement de votre projet Node.js
  3. Cliquez sur Accepter pour autoriser les modifications du dossier

Vous pouvez maintenant charger des fichiers à partir de l’arborescence de gauche :

Panneau des sources de Chrome DevTools.
Panneau des sources de Chrome DevTools.

Cliquez sur n’importe quel numéro de ligne pour définir un point de terminaison ou endpoint indiqué par un marqueur bleu.

Le débogage est basé sur des points de terminaison. Ceux-ci spécifient l’endroit où le débogueur doit mettre en pause l’exécution du programme et montrer l’état actuel du programme (variables, pile d’appels, etc.)

Vous pouvez définir un nombre quelconque de points de terminaison dans l’interface utilisateur. Une autre option consiste à placer une instruction debugger ; dans votre code, qui s’arrête lorsqu’un débogueur est attaché.

Chargez et utilisez votre application web pour atteindre l’instruction où un point de terminaison est placé. Dans l’exemple ici, http://localhost:3000/ est ouvert dans un navigateur quelconque, et DevTools arrête l’exécution à la ligne 44 :

Point de terminaison Chrome.
Point de terminaison Chrome.

Le panneau de droite montre :

  • Une rangée d’icônes d’action (voir ci-dessous).
  • Un volet Surveiller vous permet de surveiller les variables en cliquant sur l’icône + et en entrant leurs noms.
  • Un volet Points d’arrêt affiche une liste de tous les points d’arrêt et permet de les activer ou de les désactiver.
  • Le volet Scope affiche l’état de toutes les variables locales, de module et globales. Vous inspecterez ce volet le plus souvent.
  • Le volet Call Stack montre la hiérarchie des fonctions appelées pour atteindre ce point.

Une rangée d’icônes d’action est affichée au-dessus de Paused on breakpoint:

Chrome breakpoint icons
Icônes de point d’arrêt de Chrome.

De gauche à droite, celles-ci exécutent les actions suivantes :

  • resume execution : Continuer le traitement jusqu’au prochain point d’arrêt
  • step over : Exécuter la commande suivante mais rester dans le bloc de code actuel – ne pas sauter dans une fonction qu’elle appelle
  • step into : Exécuter la commande suivante et sauter dans n’importe quelle fonction si nécessaire
  • step out : Continuer le traitement jusqu’à la fin de la fonction et revenir à la commande appelante
  • step : Similaire à step into, sauf qu’il ne sautera pas dans les fonctions asynchrones
  • deactivate : Désactiver tous les points d’arrêt
  • pause on exception : Arrêter le traitement lorsqu’une erreur se produit.

Points d’arrêt conditionnels

Il est parfois nécessaire d’exercer un peu plus de contrôle sur les points d’arrêt. Imaginez que vous ayez une boucle qui a effectué 1 000 itérations, mais que vous ne soyez intéressé que par l’état de la dernière :


for (let i = 0; i < 1000; i++) {
  // set breakpoint here
}

Plutôt que de cliquer sur resume execution 999 fois, vous pouvez cliquer avec le bouton droit de la souris sur la ligne, choisir Ajouter un point d’arrêt conditionnel, et saisir une condition telle que i = 999:

Chrome conditional breakpoint
Point d’arrêt conditionnel chromé.

Chrome affiche les points d’arrêt conditionnels en jaune plutôt qu’en bleu. Dans ce cas, le point d’arrêt n’est déclenché qu’à la dernière itération de la boucle.

Points de journalisation

Les points de journalisation implémentent effectivement console.log() sans aucun code ! Une expression peut être sortie lorsque le code exécute une ligne quelconque, mais elle n’arrête pas le traitement, contrairement à un point d’arrêt.

Pour ajouter un point de journalisation, cliquez avec le bouton droit de la souris sur n’importe quelle ligne, choisissez Ajouter un point de journalisation et saisissez une expression, par exemple 'loop counter i', i:

Point de journalisation Chrome.
Point de journalisation Chrome.

La console DevTools affiche loop counter i: 0 à loop counter i: 999 dans l’exemple ci-dessus.

Utilisez VS Code pour déboguer les applications Node.js

VS Code, ou Visual Studio Code, est un éditeur de code gratuit de Microsoft qui est devenu populaire auprès des développeurs web. L’application est disponible pour Windows, macOS et Linux et est développée à l’aide de technologies web dans le framework Electron.

VS Code prend en charge Node.js et possède un client de débogage intégré. La plupart des applications peuvent être déboguées sans aucune configuration ; l’éditeur lancera automatiquement le serveur et le client de débogage.

Ouvrez le fichier de départ (tel que index.js), activez le volet Exécution et débogage, cliquez sur le bouton Exécution et débogage, et choisissez l’environnement Node.js. Cliquez sur n’importe quelle ligne pour activer un point d’arrêt représenté par une icône en forme de cercle rouge. Ensuite, ouvrez l’application dans un navigateur comme précédemment – VS Code arrête l’exécution lorsque le point d’arrêt est atteint :

Point d'arrêt VS Code.
Point d’arrêt VS Code.

Les volets Variables, Watch, Call Stack et Breakpoints sont similaires à ceux présentés dans Chrome DevTools. Le volet Loaded Scripts montre quels scripts ont été chargés, bien que beaucoup soient internes à Node.js.

La barre d’outils des icônes d’action vous permet de :

  • resume execution : Continuer le traitement jusqu’au prochain point d’arrêt
  • step over : Exécuter la commande suivante mais rester dans la fonction actuelle – ne pas sauter dans une fonction qu’elle appelle
  • step into : Exécuter la commande suivante et sauter dans n’importe quelle fonction qu’elle appelle
  • step out : Poursuivre le traitement jusqu’à la fin de la fonction et revenir à la commande appelante
  • restart : Redémarrer l’application et le débogueur
  • stop : Arrêter l’application et le débogueur

Comme pour Chrome DevTools, vous pouvez cliquer avec le bouton droit de la souris sur n’importe quelle ligne pour ajouter des points d’arrêt conditionnels et des points de journalisation.

Pour plus d’informations, reportez-vous à Débogage dans Visual Studio Code.

Configuration avancée du débogage dans VS Code

Une configuration plus poussée de VS Code peut être nécessaire si vous souhaitez déboguer du code sur un autre périphérique, une machine virtuelle, ou si vous devez utiliser des options de lancement alternatives telles que nodemon.

VS Code stocke les configurations de débogage dans un fichier launch.json situé dans un répertoire .vscode de votre projet. Ouvrez le volet Exécution et débogage, cliquez sur créer un fichier launch.json, et choisissez l’environnement Node.js pour générer ce fichier. Un exemple de configuration est fourni :

Configuration du débogueur VS Code.
Configuration du débogueur VS Code.

Un nombre illimité de réglages de configuration peuvent être définis en tant qu’objets dans le tableau "configurations". Cliquez sur Ajouter une configuration… et sélectionnez une option appropriée.

Une configuration Node.js individuelle peut soit :

  1. Lancer un processus lui-même, ou
  2. Se joindre à un serveur Web Socket de débogage, peut-être exécuté sur une machine distante ou un conteneur Docker.

Par exemple, pour définir une configuration nodemon, sélectionnez Node.js : Nodemon Setup et modifiez le script d’entrée « programme » si nécessaire :

{
  // custom configuration
  "version": "0.2.0",
  "configurations": [
    {
      "console": "integratedTerminal",
      "internalConsoleOptions": "neverOpen",
      "name": "nodemon",
      "program": "${workspaceFolder}/index.js",
      "request": "launch",
      "restart": true,
      "runtimeExecutable": "nodemon",
      "skipFiles": [
        "<node_internals>/**"
      ],
      "type": "pwa-node"
    }
  ]
}

Enregistrez le fichier launch.json et nodemon (le nom de la configuration) apparaît dans la liste déroulante en haut du volet Lancer et déboguer. Cliquez sur l’icône verte d’exécution pour commencer à utiliser cette configuration et lancer l’application à l’aide de nodemon :

Déboguage VS Code avec nodemon.
Déboguage VS Code avec nodemon.

Comme auparavant, vous pouvez ajouter des points d’arrêt, des points d’arrêt conditionnels et des points de journalisation. La principale différence est que nodemon redémarre automatiquement votre serveur lorsqu’un fichier est modifié.

Pour plus d’informations, reportez-vous à Configurations de lancement du code VS.

Les extensions VS Code suivantes peuvent également vous aider à déboguer du code hébergé sur des environnements de serveurs distants ou isolés :

  • À distance – Conteneurs : Connectez-vous à des applications exécutées dans des conteneurs Docker
  • À distance – SSH : Connectez-vous à des applications exécutées sur un serveur distant
  • Remote – WSL : Connectez-vous à des applications fonctionnant sur le sous-système Windows pour Linux (WSL).

Autres options de débogage Node.js

Le Node.js Debugging Guide fournit des conseils pour une gamme d’éditeurs de texte et d’IDE, y compris Visual Studio, JetBrains WebStorm, Gitpod et Eclipse. Atom propose une extension node-debug, qui intègre le débogueur Chrome DevTools dans l’éditeur.

Une fois que votre application est en ligne, vous pouvez envisager d’utiliser des services de débogage commerciaux tels que LogRocket et Sentry.io, qui peuvent enregistrer et lire les erreurs client et serveur rencontrées par de vrais utilisateurs.

Résumé

Historiquement, le débogage de JavaScript a été difficile, mais il y a eu d’énormes améliorations au cours de la dernière décennie. Le choix est aussi bon – sinon meilleur – que ceux fournis pour d’autres langages.

Utilisez l’outil le plus pratique pour localiser un problème. Il n’y a rien de mal à utiliser console.log() pour une recherche rapide de bogues, mais Chrome DevTools ou VS Code peuvent être préférables pour des problèmes plus complexes. Ces outils peuvent vous aider à créer un code plus robuste, et vous passerez moins de temps à corriger les bogues.

Quelle pratique de débogage Node.js a votre préférence ? Partagez-la dans la section des commentaires ci-dessous !

Craig Buckler

Développeur web, écrivain et conférencier britannique indépendant. Il existe depuis longtemps et s'insurge contre les normes et les performances.