How to debug Node.js Code Using Multiple Tools

Mar 16, 2022
A magnifying glass over node debug

But, developing software is a complex task, and the Node.js code will fail at some point. This tutorial demonstrates various tools to help diagnose software and determine the root of the issue.

Let's begin.

Debugging Overview

"Debugging" is the title used to describe the different methods to fix software bugs. The process of fixing a problem is usually straightforward. The root of the issue could be a lot more complicated and require a lot of head scratching.

In the following paragraphs, we will discuss three general types of error you'll encounter.

Syntax Errors

The code you write is not following the conventions of the language -- such as where you leave out the closing bracket, or you mispelling a sentence, like console.lag(x).

A good code editor can help spot common problems by:

  • Valid or invalid statements that are color coded
  • Type-checking variables
  • Functions for auto-completing and variable names
  • The brackets should be highlighted to match.
  • Auto-indenting code blocks
  • Detection of code that is not reachable
  • Refactoring complicated functions

A code linter like ESLint will also report syntax mistakes, incorrect indentation, as well as undeclared variables. ESLint is the name of a Node.js software that you can download worldwide using:

npm i eslint -g

You can check JavaScript documents from the command line using:

eslint mycode.js

...but it's much easier to utilize the editor plugin such as ESLint for Visual Studio Code and the linter-eslint plugin for Atom that will automatically validate code as you type it:

ESlint in VS Code
ESlint inside VS Code.

Logic Errors

The program runs, however it isn't working as you'd like. For example, a user's login isn't completed when they request it; the report displays incorrect numbers; data is not fully saved to a database; and so on.

Logic errors can be due to:

  • Using the wrong variable
  • Untrue conditions, e.g. if (a > 5) rather than if (a > 5)
  • Calculations which do not take into account operator precedence e.g. 1+2*3 result in 7 rather than 9.

Runtime (or Execution) Errors

An error only becomes evident after the program is run and can lead to a crash. Runtime errors could be caused by:

  • Dividing by a variable that has been set to zero
  • In the process of accessing an array item that does not exist
  • Try to write into a read-only database

Logic and runtime errors are more difficult to spot however, the following strategies for development may help:

  1. Use Test-Driven Development: TTD recommends that you create tests prior to the time a function is developed, e.g. FunctionY returns X after Z is used as the parameter. These tests are run during the initial development and afterward to verify that it continues to run as expected.
  2. Use an issue tracking system:There is nothing worse than an email claiming "Your software does not work"! Issue tracking systems allow you to keep track of specific issues, document reproduction steps, determine priorities, assign developers, and monitor the development of fixes.

It is possible to encounter Node.js bugs, but this section outlines methods to identify that mysterious error.

Set Appropriate Node.js Environment Variables

Environment variables set in the host operating system can influence Node.js applications and module configurations. Most commonly, it is NODE_ENV that is typically changed to development during debugging or in production mode when it is running on the live server. Set environment variables on macOS or Linux with:

NODE_ENV=development

or at or at the (classic) Windows command prompt:

set NODE_ENV=development

Or Windows Powershell:

$env:NODE_ENV="development"

The popular Express.js framework Setting NODE_ENV to development disables template file caching and outputs verbose errors, which can be helpful when debugging. Some modules might offer similar features as well, so you could apply a NODE_ENV setting to your application, e.g.

// running in development mode? const devMode = (process.env.NODE_ENV !== 'production');
 
 if (devMode) 
 console.log('application is running in development mode');
 

It is also possible to use the util.debuglog method to generate error messages on a predetermined basis, e.g.

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

The program will only print the log message when NODE_DEBUG has been set to myapp or a wildcard , such as * or my*.

Make use of Node.js Command Line Options

Node scripts are generally executed using node, followed by the title of the entry script.

node app.js

You can also define command line options to control the various aspects of running time. Useful flags for debugging include:

  • --check  
      Check the syntax of the script before running the script
  • --trace-warnings  
      output a stack trace that is generated when JavaScript Promises don't resolve or reject
  • --enable-source-maps  
      display source maps when you use a transpiler such as TypeScript
  • --throw-deprecation  
      warn when deprecated Node.js features are used
  • --redirect-warnings=file  
      Output warnings to a file instead of warnings to a file, not
  • --trace-exit  
      produce a trace of the stack when process.exit() is invoked.

Input messages to the Console

Outputting a console message is one of the most straightforward methods to test a Node.js application.

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

A few developers know that there are a variety of other console options:

Console Method Description
.log(msg) standard console message
.log('%j', obj) output object is the result of a small JSON string
.dir(obj, opt) property of objects that pretty-print
.table(obj) output arrays and objects in tabular format
.error(msg) an error message
.count(label) increment a named counter and output
.countReset(label) reset a named counter
.group(label) make an indentation on a message
.groupEnd(label) Stopping an entire group
.time(label) Starts a designated timer
.timeLog(label) reports the elapsed time
.timeEnd(label) Stops a timer that is named
.trace() output a stack trace (a list of all the functions that were called)
.clear() clear the console

console.log() also accepts a list of comma-separated values:

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

...although ES6 destructuring offers similar results with less effort

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

Console.dir() is a command that prints the properties of objects. console.dir() command print object's properties pretty similarly to util.inspect():

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

Console Controversy

A few developers suggest that you should not utilize console.log() due to:

  • It is possible to modify something, or even forget to remove it, and
  • There's no reason to do it when there are better debugging choices.

Don't believe anyone who claims that they don't use console.log()! Logging is quick and dirty However, everybody uses it at least once in their lives. Utilize the tool or method you prefer. Fixing a bug is more important than the technique that you use to identify it.

Utilize a third-party logging system

Third-party log systems offer more sophisticated features such as messages levels, volume, sorting, file output and profiling, as well as reporting and much more. Popular solutions include loglevel, cabin, morgan, pino, signale, the storyboard, tracer and winston.

Use the V8 Inspector

The V8 JavaScript engine provides a debugging application to use to debug your application in Node.js. Launch an application with node inspect, e.g.

node inspect app.js

The debugger pauses at the start of the line. It then shows the debug> prompt

$ node inspect .\mycode.js
  One const number = 10.
3. (i = 0, (i 

Click help for the list of commands. It is possible to navigate through the program by typing:

  • con or C: continue execution
  • next or n: run the next command
  • step or step: step into a function being called
  • out or o Step from a function, then go back to the call statement
  • pause: pause running code
  • watch('myvar'): watch a variable
  • setBreakPoint() or sb(): set a breakpoint
  • restart Restart the script
  • .exit or Ctrl  Cmd: exit the debugger

Admittedly, this debugging option is time-consuming and unwieldy. Only use it when there's an alternative, for instance, in the event that you're using code on a remote server and you're unable to connect elsewhere or install additional software.

Use the Chrome Browser to debug Node.js Code

Want to know what we did to increase our volume by more than 1000%?

Join the 20,000+ who get our weekly newsletter with insider WordPress tips!

For debugging a standard web application, start it using the option -inspect to activate for the V8 Debugger's Web Socket server:

Node --inspect index.js

Note:

  • index.js is presumed to represent the entry script for the application.
  • Ensure you use the option --inspect with double dashes to make sure you don't launch the client for debugging using text.
  • You could utilize nodemon instead of node when you'd like to restart the application when a file is changed.

By default, the debugger is only able to accept connections from the local machine. If you're running your application on another device, virtual machine, or Docker container, you can use:

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

It is also possible to make use of the option --inspect-brk instead of --inspect to halt running (set a breakpoint) in the initial line, allowing you to step through the code starting from beginning.

Start a browser with Chrome and enter Chrome://inspect into the address bar in order to display local and networked devices:

Chrome inspect tool
Chrome inspection tool.

If your Node.js application isn't displaying as a Remote Source or you are unable to find it, then:

  • Select Open the dedicated DevTools to Node and select the address and port or
  • Look for the network target you want to discover Select to configure Add the IP address and port for the device on which it's running.

Hit the Target's inspect link to start DevTools' DevTools Debugger Client. It should be well-known to any person who has employed DevTools in the past for client-side debugging:

Chrome DevTools
Chrome DevTools.

Change on your Sources panel. You can open any file using Cmd Ctrl +P and then entering the file's name (such as index.js).

It's also easier to add your project's folder to the workspace. This lets you load, edit, and save files directly through DevTools (whether you think that's an ideal idea is another issue!)

  1. Click + Add folder to the workspace
  2. Select the location for your Node.js project
  3. Hit Agreeto let file changes be made

Now you can load files from the left-hand directory tree:

Chrome DevTools Sources panel
Chrome DevTools Sources panel.

Simply click any line to establish a breakpoint indicated by the blue marker.

Debugging relies in breakpoints. The breakpoints define where the debugger should pause program execution. They also show the current state of the program (variables or call stacks, and so on.)

It is possible to define any number of breakpoints in your user's interface. Another possibility is to include a debugger; statement into the code that stops once a debugger has been attached.

Use your internet application to get to the line where a breakpoint is set. In the example here, http://localhost:3000/ is opened in any browser, and DevTools will halt execution on line 44:

Chrome breakpoint
Chrome breakpoint.

The panel on the right shows:

  • Action icons in a row (see further below).
  • A Watch pane allows you to observe variables through on the + icon, then typing the names of them.
  • A breakpoints pane displays a breakdown of all breakpoints available and allows them to be turned off or activated.
  • Scope pane Scope pane shows the state of each local, module, and global variables. It is the pane you'll be checking the most frequently.
  • A Call Stack pane displays the hierarchy of calls that have been made to arrive at this level.

The row of icons for action is shown above The action icons are paused at breakpoints:

Chrome breakpoint icons
Chrome breakpoint icons.

From right to left, from left to right:

  • resume execution: Continue working until the next breakpoint
  • step-over The next step is to execute the command, but remain in the block of code that is currently running Do not dive into any of the functions it invokes.
  • Step into Step into HTML0: Perform the following command, and then jump into the next function as necessary
  • remove: Continue processing to the conclusion of the operation before returning to the calling command
  • step: Similar to the step in but it does not be able to jump into async functions
  • deactivate all breakpoints
  • Pauses in the event of an exception: Halt processing when an error is detected.

Conditional Breakpoints

Sometimes, it's essential to have some more control over breakpoints. Consider a loop that completed 1,000 times but you're just interested in what happened to the first one.


 for (let i = 0; i 

Instead of pressing resume execution 999 times, you can right-click the line, choose the option to add a conditional breakpoint then specify a specific condition, such as the value i = 99:

Chrome conditional breakpoint
Chrome conditional breakpoint.

Chrome shows conditional breakpoints in yellow rather than blue. In this instance, the breakpoint will only be activated upon the final iteration of the loop.

Log Points

Log points efficiently allow you to implement console.log() with no codes! Expressions can be output when the code executes any line. However, it will not stop processing like a breakpoint.

To create a log point, just right-click on any line, then choose Add log point then type in an expression, e.g. "loop counter i" (i):

Chrome logpoint
Chrome log point.

The DevTools console outputs loop counter i: 0. to loop counter i.e. 999 in the example above.

Use VS Code to Debug Node.js Applications

VS Code is compatible with Node.js and has the built-in debugging software. Many applications can be debugged without any setup; the editor will automatically start the debugging servers and the client.

Then, open the beginning file (such like index.js) and then, in the Run and Debug pane, then click the run and debug button, and choose to open the Node.js environment. Click any line to activate a breakpoint shown by a red circle. After that, you can open the app in a browser as before -- VS Code stops execution once it reaches the breakpoint:

VS Code breakpoint
VS Code breakpoint.

The action icon toolbar can be used to:

  • resume execution to continue processing until the next breakpoint
  • step over Step over: Perform the following step, however stay within the function you are currently usingDo not enter the function that it is calling
  • Step into step into: Enter the next command, and then jump into the function it calls
  • Step out: Continue processing to the end of the function and then return to the call command
  • Startthe application and debugger
  • Stopthe application, and the debugger

Similar to Chrome DevTools, you can right-click any line to include conditional breakpoints as well as Log points.

For more information, refer to Debugging in Visual Studio Code.

VS Code Advanced Debugging Configuration

Additionally, VS Code configuration may be required if you wish to run code debugging on a different device, a virtual machine, or to use alternative launch options such as nodemon.

VS Code stores debugging configurations inside a launch.json file inside a .vscode directory in your project. Start the Run and Debugging pane. Click to to create an launch.json file select to use the Node.js environment to make this file. The following example configuration can be found:

VS Code debugger configuration
VS Code debugger configuration.

The various configuration settings are available in the "configurations" array. Simply click on Add Configuration... and choose the appropriate option.

An individual Node.js configuration can either:

  1. The process can be initiated by itself or
  2. Attach to the debugging Web Socket server, perhaps that is running on a remote device or Docker container.

For example, to define an Nodemon configuration, choose Node.js Setup: Nodemon and then modify the "program" entry script as necessary:


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

Save the launch.json file and nodemon(the configuration "name") is displayed in the drop-down list on the right side in the Run and Debug pane. Click the green run icon to activate that configuration. Launch the application with nodemon.

VS Code debugging with nodemon
VS Code debugging with nodemon.

As before, you can create breakpoints, conditional breakpoints or log points. One of the main differences is that nodemon automatically start your server whenever an application is changed.

For more information, go to the configurations for VS Code Launch.

The following VS Code extensions can also assist you in debugging code that is hosted on remote or isolated server systems:

  • Remote Containers connect to applications that are running inside Docker containers
  • Remote SSH Connect to applications that are running on remote servers
  • Remote -- WSL Connect to programs that run in Windows Subsystem for Linux (WSL). Windows Subsystem for Linux (WSL).

Others Node.js Debugging Options

The Node.js Debugging Guide provides advice for various editors for text and IDEs which include Visual Studio, JetBrains WebStorm, Gitpod, and Eclipse. Atom has a node-debug plugin that incorporates with the Chrome DevTools debugger into the editor.

Once your application is live You may want to consider using commercial debugging services such as LogRocket and Sentry.io, which can record and playback client and server errors experienced by real-world clients.

Summary

Make use of whatever tool you can for locating a issue. It's fine to use console.log() to speed up bug hunting, but Chrome DebTools and VS Code may be preferable to tackle more complicated problems. They can assist you to develop more secure code and will help you spend less time trying to fix problems.

What Node.js practices is your most dependable practice? Share in the comments section below!

Reduce time, money and improve site performance by:

  • Help is available immediately from WordPress experts in hosting, 24 hours a day.
  • Cloudflare Enterprise integration.
  • Global audience reach with 29 data centers worldwide.
  • Optimization through the integrated Application to monitor performance.