Node.js is een JavaScript runtime die is gebaseerd op dezelfde V8 engine die wordt gebruikt in de Chrome browser van Google. Het wordt vaak gebruikt om cross-platform server-side en terminal applicaties te bouwen. Node.js is de afgelopen tien jaar steeds populairder geworden, omdat het eenvoudig te installeren is, eenvoudig gebruikt kan worden, snel is en omdat het webontwikkelaars aan de clientzijde in staat stelt hun vaardigheden elders te gebruiken.

Softwareontwikkeling blijft echter een complexe taak, en je Node.js code zal op een gegeven moment falen. Deze tutorial toont verschillende tools om applicaties te helpen debuggen en de oorzaak van een probleem te vinden.

Laten we meteen van start gaan.

Bekijk onze videogids over het debuggen van Node.js code

Overzicht debugging

“Debugging” is de naam die wordt gegeven aan de verschillende manieren om softwaredefecten te verhelpen. Het verhelpen van een bug is vaak eenvoudig. Het vinden van de oorzaak van de bug kan aanzienlijk complexer zijn en zorgt vaak voor meerdere uren aan hoofdpijn.

De volgende secties beschrijven drie algemene soorten fouten die je tegenkomt.

Syntax fouten

Je code volgt niet de regels van de taal, bijvoorbeeld wanneer je een haakje achterwege laat of een statement zoals console.lag(x) verkeerd spelt.

Een goede code-editor kan helpen bij het opsporen van veelvoorkomende problemen door:

  • Kleurcodering geldige of ongeldige statements
  • Checken van variabeletypes
  • Automatisch aanvullen functies en namen van variabelen
  • Highlighten van overeenkomende haakjes
  • Codeblokken automatisch laten inspringen
  • Detecteren onbereikbare code
  • Refactoring van rommelige functies

Gratis editors als VS Code en Atoms bieden prima ondersteuning voor Node.js, JavaScript en TypeScript (wat transpileert naar JavaScript). Basic problemen met de syntax kunnen meestal worden gespot voordat je je code opslaat en test.

Een code linter zoals ESLint zal daarnaast syntaxfouten, slechte inspringing en niet-gedeclarede variabelen rapporteren. ESLint is een Node.js tool die je globaal kan installeren met:

npm i eslint -g

Je kan JavaScript bestanden controleren vanaf de command line met:

eslint mycode.js

…maar het is gemakkelijker om een editor plugin te gebruiken, zoals ESLint voor VS Code of linter-eslint voor Atom, die automatisch code valideren terwijl je typt:

ESlint in VS Code
ESlint in VS Code.

Fouten in de logica

Je code werkt, maar niet zoals je had verwacht. Een gebruiker wordt bijvoorbeeld niet uitgelogd wanneer hij daarom vraagt; een rapport toont onjuiste cijfers; gegevens worden niet volledig opgeslagen in een database; etc.

Logicafouten kunnen worden veroorzaakt door:

  • Het gebruik van de verkeerde variabele
  • Onjuiste conditions, bijv. if (a > 5) in plaats van if if (a < 5)
  • Berekeningen die geen rekening houden met de voorrang van de operator, bijvoorbeeld 1+2*3 resulteert in 7 in plaats van 9.

Runtime (of executie) fouten

Een fout wordt pas duidelijk wanneer de applicatie wordt uitgevoerd, wat vaak leidt tot een crash. Runtime fouten kunnen worden veroorzaakt door:

  • Het delen door een variabele die op nul is ingesteld
  • Een poging om toegang te krijgen tot een array-item dat niet bestaat
  • Het proberen om te schrijven naar een alleen-lezen bestand

Logica en runtime fouten zijn moeilijker te herkennen, hoewel de volgende ontwikkelingstechnieken kunnen helpen:

  1. Gebruik Test-Driven Development: TTD moedigt je aan om tests te schrijven voordat een functie wordt ontwikkeld, bijvoorbeeld X wordt teruggegeven van function Y wanneer Z wordt doorgegeven als een parameter. Deze tests worden uitgevoerd tijdens de initiële ontwikkeling en daaropvolgende updates om ervoor te zorgen dat de code blijft werken zoals verwacht.
  2. Gebruik een Issue Tracking System: Er is niets erger dan een e-mail waarin staat “Je software werkt niet”! Met Issue Tracking Systems kan je specifieke problemen vastleggen, reproductiestappen documenteren, prioriteiten bepalen, developers toewijzen en de voortgang van oplossingen bijhouden.
  3. Gebruik Source Control: Een Source Control System zoals Git zal je helpen bij het backuppen van code, het beheren van revisies en het identificeren waar een bug zijn oorsprong had. Online repositories, waaronder Github en Bitbucket, bieden gratis ruimte en tools voor kleinere of open-source projecten.

Je zal nog steeds Node.js bugs tegenkomen, maar de volgende secties beschrijven manieren om die ongrijpbare fout te lokaliseren.

De juiste Node.js omgevingsvariabelen instellen

Omgevingsvariabelen (environment variables) die zijn ingesteld in het host-besturingssysteem kunnen Node.js applicatie- en module-instellingen beheren. De meest voorkomende is NODE_ENV, die meestal wordt ingesteld op ontwikkelingsomgevingen bij het debuggen of op productie bij het uitvoeren op een live server. Stel omgevingsvariabelen in op macOS of Linux met het commando:

NODE_ENV=development

of bij de (klassieke) Windows opdrachtprompt:

set NODE_ENV=development

of Windows Powershell:

$env:NODE_ENV="development"

In het populaire Express.js framework schakelt het instellen van NODE_ENV op development het cachen van templates uit en zorgt het voor de output van uitgebreide foutmeldingen, wat nuttig kan zijn bij het debuggen. Andere modules kunnen vergelijkbare features bieden en je kunt een NODE_ENV-voorwaarde toevoegen aan uw toepassingen, bijv.

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

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

Je kan ook de util.debuglog methode van Node gebruiken om foutmeldingen voorwaardelijk uit te voeren, bijv.

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

Deze applicatie zal het logbericht alleen outputten wanneer NODE_DEBUG is ingesteld op myapp of een wildcard zoals * of my*.

Node.js commandline opties gebruiken

Node scripts worden meestal gestart met node gevolgd door de naam van het entry script:

node app.js

Je kan ook command line opties instellen om verschillende runtime-aspecten te besturen. Handige flags voor het debuggen zijn:

  • --check
    checkt syntax script zonder uit te voeren
  • --trace-warnings
    output een stack trace wanneer JavaScript Promises niet resolven of rejecten
  • --enable-source-maps
    laat source maps zien bij gebruik van een transpiler zoals TypeScript
  • --throw-deprecation
    waarschuwen wanneer verouderde Node.js functies worden gebruikt
  • --redirect-warnings=file
    output waarschuwing naar een bestand in plaats van stderr
  • --trace-exit
    output een stack trace wanneer process.exit() wordt gecalld.

Output berichten naar de console

Het uitvoeren van een consolebericht is een van de eenvoudigste manieren om een Node.js  applicatie te debuggen:

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

Weinig ontwikkelaars weten dat er veel andere console methoden zijn:

Console methode Beschrijving
.log(msg) standaard console bericht
.log('%j', obj) output object als een compacte JSON string
.dir(obj, opt) pretty-print object properties
.table(obj) output arrays en objecten in tabelvorm
.error(msg) een error bericht
.count(label) increment een named counter en output
.countReset(label) reset een named counter
.group(label) een groep berichten laten inspringen
.groupEnd(label) een groep terminaten
.time(label) start een named timer
.timeLog(label) meldt de verstreken tijd
.timeEnd(label) stopt een named timer
.trace() output een stack trace (een lijst van alle gemaakte functie calls)
.clear() wist de console

console.log() accepteert ook een lijst met door komma’s gescheiden waarden:

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

…hoewel ES6 destructuring vergelijkbare output biedt met minder inspanning:

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

Het console.dir() commando pretty-print object properties op dezelfde manier als util.inspect():

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

Console controversie

Sommige ontwikkelaars beweren dat je onsole.log() nooit moet gebruiken omdat:

  • Je de code wijzigt en iets onbewust kan veranderen of vergeten te verwijderen, en
  • Het is sowieso niet nodig wanneer er betere debugopties zijn.

Geloof niemand die beweert dat ze nooit console.log() gebruiken! Logging is snel en maakt je handen vies, maar iedereen gebruikt het op een gegeven moment. Gebruik de tool of techniek die jij wil. Het oplossen van een bug is belangrijker dan de methode die je gebruikt om het te vinden.

Een extern loggingsysteem gebruiken

Externe loggingsystemen bieden meer geavanceerde functies, zoals berichtenniveaus, verbositeit, sorteren, bestandsoutput, profilering, rapportage en meer. Populaire oplossingen zijn onder meer cabinloglevelmorganpinosignalestoryboardtracer, en winston.

De V8 inspector gebruiken

De V8 JavaScript engine biedt een debugging client die je kan gebruiken in Node.js. Start een applicatie met behulp van node inspect, bijv.

node inspect app.js

De debugger pauzeert bij de eerste regel en geeft een debug> prompt weer:

$ 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>

Vul help in om een lijst met commando’s te zien. Je kan de applicatie doorlopen door het volgende in te voeren:

  • cont of c: ga verder met executie
  • next of n: voer het volgende commando uit
  • step of s: stap in een functie die wordt gecalld
  • out of o: stap uit een functie en ga terug naar het callende statement
  • pause: pauzeer het runnen van de code
  • watch(‘myvar’): bekijk een variable
  • setBreakPoint() of sb(): stel een breakpoint in
  • restart: herstart het script
  • .exit of Ctrl | Cmd + D: sluit de debugger af

Toegegeven, deze debug optie is tijdrovend en onhandig. Gebruik het alleen als er geen andere optie is, zoals wanneer je code uitvoert op een externe server en geen verbinding kunt maken vanaf een andere server of extra software kunt installeren.

De Chrome browser gebruiken om Node.js code te debuggen

De hierboven gebruikte optie Node.js inspect optie start een websocketserver die luistert op localhost poort 9229. Het start ook een op tekst gebaseerde debugging client, maar het is mogelijk om grafische clients te gebruiken — zoals degene die is ingebouwd in Google Chrome en Chrome gebaseerde browsers zoals Chromium, Edge, Opera, Vivaldi en Brave.

Om een typische webapplicatie te debuggen, start je deze met de optie -inspect om de Web Socket server van de V8 debugger in te schakelen:

node --inspect index.js

Opmerking:

  • index.js wordt hier verondersteld het entry script van de applicatie te zijn.
  • Zorg ervoor dat je --inspect gebruikt met dubbele streepjes om ervoor te zorgen dat je de op tekst gebaseerde debugger client niet start.
  • Je kan nodemon in plaats van node gebruiken als je de applicatie automatisch wilt herstarten wanneer een bestand wordt gewijzigd.

Standaard accepteert de debugger alleen inkomende verbindingen van de lokale computer. Als je de toepassing op een ander apparaat, een virtuele machine of een Docker container uitvoert, gebruik je:

node --inspect=0.0.0.0:9229 index.js
node inspect option
node inspect option.

Je kan ook --inspect-brk gebruiken in plaats van --inspect om de verwerking te stoppen (een breakpoint instellen) op de eerste regel, zodat je de code vanaf het begin kunt doorlopen.

Open een Chrome-gebaseerde browser en voer chrome://inspect in de adresbalk in om lokale en netwerkapparaten te bekijken:

Chrome Inspect tool
Chrome Inspect tool.

Als je Node.js applicatie niet wordt weergegeven als een Remote Target, heb je deze opties:

  • Klik Open dedicated DevTools for Node en kies het adres en poort, of
  • Check Discover network targets, klik Configure en voeg dan het IP adres en de poort toe van het apparaat waarop het wordt uitgevoerd.

Klik op de inspect link van het Target om de DevTools debuggerclient te starten. Dit zou bekend moeten zijn voor iedereen die DevTools heeft gebruikt voor client-side code debugging:

Chrome DevTools
Chrome DevTools.

Schakel over naar het Sources paneel. Je kan elk bestand openen door op Cmd | Ctrl + P te drukken en de bestandsnaam (bijv. index.js) in te voeren.

Het is echter gemakkelijker om je projectmap toe te voegen aan de workspace. Hiermee kun je bestanden rechtstreeks vanuit DevTools laden, bewerken en opslaan (of het een goed idee is, is een andere zaak!)

  1. Klik op + Add folder to workspace
  2. Selecteer de locatie van je Node.js project
  3. Druk op Agree om bestandswijzigingen toe te staan

Je kan nu bestanden laden vanuit de linker directory-tree:

Sources paneel Chrome DevTools
Sources paneel Chrome DevTools.

Klik op een regelnummer om een breakpoint in te stellen dat wordt aangegeven door een blauwe markering.

Debugging is gebaseerd op breakpoints. Deze specificeren waar de debugger de uitvoering van het programma moet pauzeren en de huidige status van het programma moet tonen (variabelen, call stack, etc.)

Je kan elk aantal breekpunten definiëren in de gebruikersinterface. Een andere optie is het plaatsen van een debugger; statement in je code, die stopt wanneer een debugger is gekoppeld.

Laad en gebruik je webapplicatie om het statement te bereiken waar een breakpoint is ingesteld. In het voorbeeld hier, is http://localhost:3000/ geopend in een browser, en DevTools zal stoppen met de uitvoering op regel 44:

Chrome breakpoint
Chrome breakpoint.

Het rechterpaneel toont:

  • Een rij actiepictogrammen (zie hieronder).
  • Met een Watch paneel kun je variabelen monitoren door op het + -pictogram te klikken en hun namen in te voeren.
  • Een Breakpoints paneel toont een lijst met breakpoints maakt het mogelijk deze in of uit te schakelen.
  • Een Scope paneel toont de status van alle lokale, module en globale variabelen. Dit deelvenster inspecteer je het vaakst.
  • Een Call Stack paneel toont de hiërarchie van functies die worden gecalld om dit punt te bereiken.

Er wordt een rij van actiepictogrammen weergegeven boven Paused on breakpoint:

Chrome breakpoint pictogrammen
Chrome breakpoint pictogrammen.

Van links naar rechts voeren deze de volgende acties uit:

  • resume execution: ga verder met verwerken tot het volgende breakpoint
  • step over: voer het volgende commando uit maar blijf binnen het huidige codeblok – ga niet naar een functie die het callt
  • step into: voer het volgende commando uit en ga indien nodig naar een functie
  • step out: ga verder met het verwerken tot het einde van de functie en keer terug naar het callende commando
  • step: vergelijkbaar met step into behalve dat deze niet naar async functies springt
  • deactivate alle breakpoints
  • pause on exceptions: stopt verwerking wanneer er een fout optreedt.

Voorwaardelijke breekpunten

Soms is het nodig om wat meer controle over breakpoints te hebben. Stel je voor dat je een loopt hebt die 1.000 iteraties heeft voltooid, maar je bent alleen geïnteresseerd in de status van de laatste:


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

In plaats van 999 keer op resume execution te klikken, kun je met de rechtermuisknop op de regel klikken, Add conditional breakup kiezen en een voorwaarde invoeren zoals i = 999:

Chroom voorwaardelijk breakpoint
Chroom voorwaardelijk breakpoint.

Chrome toont voorwaardelijke breakpoints in geel in plaats van blauw. In dit geval wordt het breakpoint alleen geactiveerd bij de laatste iteratie van de loop.

Logpunten

In de praktijk implementeren logpunten console.log() zonder enige code! Een expressie kan worden uitgevoerd wanneer de code een regel uitvoert, maar het stopt de verwerking niet, in tegenstelling tot een breakpoint.

Als je een logpunt wilt toevoegen, klik je met de rechtermuisknop op een willekeurige regel, kies je Add log point en voer je een expressie in , bijvoorbeeld 'loop counter i', i:

Chrome logpunt
Chrome logpunt.

De DevTools console output loop counter i: 0 naar loop counter i: 999 in het bovenstaande voorbeeld.

VS code gebruiken om Node.js applicaties te debuggen

VS Code of Visual Studio Code is een gratis code editor van Microsoft die populair is geworden onder webdevelopers. De applicatie is beschikbaar voor Windows, macOS en Linux en is ontwikkeld met behulp van webtechnologieën in Electron framework.

VS Code ondersteunt Node.js en heeft een ingebouwde debugging client. De meeste applicaties kunnen zonder configuratie worden gedebugd; de editor zal automatisch de debugserver en client starten.

Open het startbestand (zoals index.js), activeer het deelvenster Run and Debug, klik op de knop Run and Debug en klik op de Node.js omgeving. Klik op een lijn om een breakpoint te activeren dat wordt weergegeven als een rood cirkelpictogram. Open vervolgens de applicatie in een browser zoals eerder — VS Code stopt de uitvoering wanneer het breakpoint is bereikt:

VS Code breakpoint
VS Code breakpoint.

De deelvensters VariablesWatchCall Stack, and Breakpoints zijn vergelijkbaar met die in Chrome devtools. Het deelvenster Loaded Scripts laat zien welke scripts zijn geladen, hoeveel veel hiervan intern zijn voor Node.js.

Op de werkbalk met actiepictogrammen kun je:

  • resume execution: ga verder met verwerken tot het volgende breakpoint
  • step over: voer het volgende commando uit maar blijf binnen de huidige functie – spring niet naar functies die het callt
  • step into: voer het volgende commando uit en spring naar elke functie het aanroept
  • step out: ga verder met het verwerken tot het einde van de functie en keer terug naar het callende commando
  • restart de applicatie en debugger
  • stop de applicatie en debugger

Net als Chrome DevTools kan je met de rechtermuisknop op een willekeurige regel klikken om Conditional breakpoints en Log points toe te voegen.

Raadpleeg Debugging in Visual Studio Code voor meer informatie.

Geavanceerde debuggingconfiguratie VS code

Verdere VS Code configuratie kan nodig zijn als je code op een ander apparaat of virtuele machine wil debuggen, of andere launch-opties nodig hebt zoals nodemon.

VS Code slaat debuggingconfiguraties in een launch.json bestand op in een .vscode directory in je project. Open het deelvenster Run and Debug, klik op create a launch.json file kies de Node.js omgeving om dit bestand te genereren. Een voorbeeldconfiguratie wordt gegeven:

VS Code debugger configuratie
VS Code debugger configuratie.

Je kan een onbeperkt aantal configuratie-instellingen als objecten definiëren in de array "configurations". Klik op Add Configuration… en selecteer een geschikte optie.

Een losse Node.js configuratie kan ofwel:

  1. Zelf een proces starten, of
  2. Zich koppelen aan een debugging Web Socket server, mogelijk uitgevoerd op een remote machine of Docker container.

Als je bijvoorbeeld een nodemon configuratie wilt definiëren, selecteer je Node.js: Nodemon Setup en wijzig je indien nodig het “program” entry script:

{
  // 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"
    }
  ]
}

Sla het launch.json bestand op en de nodemon (de configuratie “name”) verschijnt in de vervolgkeuzelijst bovenaan het deelvenster Run and Debug. Klik op het groene runpictogram om die configuratie te gebruiken en start de applicatie met behulp van nodemon:

VS Code debugging met nodemon
VS Code debugging met nodemon.

Net als voorheen kun je breakpoints, voorwaardelijke breakpoints en logpunten toevoegen. Het belangrijkste verschil is dat nodemon automatisch je server herstart wanneer een bestand wordt gewijzigd.

Raadpleeg voor meer informatie de VS Code Launch configuraties.

De volgende VS Code extensies kunnen je helpen bij het debuggen van code die wordt gehost op externe of geïsoleerde serveromgevingen:

  • Remote — Containers: maakt verbinding met apps die worden uitgevoerd in Doctor containers
  • Remote — SSH: maakt verbinding met apps die op een externe server worden uitgevoerd
  • Remote — WSL: maakt verbinding met apps die worden uitgevoerd op het Windows Subsystem for Linux (WSL).

Andere Node.js debuggingopties

De Node.js Debugging Guide geeft advies voor een reeks teksteditors en IDE ‘s, waaronder Visual Studio, JetBrains WebStorm, Gitpod en Eclipse. Atom biedt een node-debug extensie, die de Chrome DevTools debugger in de editor integreert.

Zodra je applicatie live is, kun je commerciële debugging diensten zoals LogRocket en Sentry.io overwegen, die client- en serverfouten kunnen opnemen en afspelen die worden ondervonden door echte gebruikers.

Samenvatting

Historisch gezien is JavaScript debugging altijd al een uitdaging geweest, maar er zijn de afgelopen tien jaar enorme verbeteringen opgetreden. De keuze is even goed — zo niet beter — als die voor andere talen.

Gebruik de tool die voor jou het meest praktisch is om een probleem te lokaliseren. Er is niets mis met console.log() voor snelle bughunting, maar Chrome DevTools of VS Code kan de voorkeur hebben voor meer complexe problemen. De tools kunnen je helpen robuustere code te maken en je zult minder tijd kwijt zijn aan het oplossen van bugs.

Wat is jouw favoriete Node.js debugging tool? Laat het ons weten in de comments hieronder!

Craig Buckler

Freelance UK web developer, writer, and speaker. Has been around a long time and rants about standards and performance.