Debugging with VSCode

As I’m working my way from console.log statements to appropriate debugging tools I’m writing this post on setting up multi-targeted debugging using VSCode for a Node application running inside a Docker container.

Index


Requirements

  1. Debug client side and server side code (multi-targeted debugging) with the same Debugging Client (VSCode)

  2. Debug an application running inside a Docker container

  3. Debugging client (VSCode) should re-attach to the process as Nodemon restarts the application on code changes


What happens when a Node process is run in the debug mode?

To debug a Node application it is started with the --inspect flag.

node --inspect index.js

The --inspect flag causes the Node application process to listen for debug commands via WebSockets on a default host and port - 127.0.0.1:9229. A debugging client such as Chrome DevTools or VSCode’s debugger can send the debug commands (set breakpoints, pause, continue, stop) on this socket and also listen for responses.

To debug a node application it is thus required to run it with the --inspect flag.


Setup Overview

vscode-debugger-setup

Github Repo for the setup


How to?

Debug a Node process running inside a Docker container?

To debug a Node application running inside a Docker container, the socket (host:port) on which the debugger listens for commands has to be exposed outside the container. To modify the default socket the following command can be used

node --inspect=0.0.0.0:9229 index.js

The debugger has been started on the host 0.0.0.0 and not 127.0.0.1 to make it accessible from outside the container. After executing the above command the debugger is listening on 0.0.0.0:9229 inside the container.

Next, we can map this to the port 9229 on the local machine using the -p flag in docker run command

docker run -p 9229:9229 <image-id>

With the above mapping set, the debugger can be accessed on the local machine on 127.0.0.1:9229. To check if it works go to the following URL in the browser

http://localhost:9229/json/list


Connect the debugging client (VSCode) to the Node process’ debug socket?

  1. Go to the root of the project directory.

  2. Open .vscode/launch.json

  3. Select the option to ‘Add Configuration’ at the bottom right of the screen

  4. Select the configuration for ‘Docker: Attach to Node’. The following default configuration will be added to launch.json

{
    "type": "node",
    "request": "attach",
    "name": "Docker: Attach to Node",
    "port": 9229,
    "address": "localhost",
    "localRoot": "${workspaceFolder}",
    "remoteRoot": "/usr/src/app",
    "protocol": "inspector"
},

Modify remoteRoot to point at the project directory inside the container.

  1. Run the Node application inside the container using docker run command

  2. Run the VSCode debugger with the Docker: Attach to Node configuration. This should attach the VSCode debugger to the running Node application inside the container.


Get VSCode to reattach the debugger automatically when Nodemon restarts the application inside the container?

Modify the Docker: Attach to Node configuration in launch.json and add the following field

{
    "restart": true
}


Setup a multi-targeted debugging allowing to debug both the server side and the client side from VSCode?

Setup configuration for debugging JavaScript running inside Chrome

  1. Install extension - ‘Debugger for Chrome’ by Microsoft

  2. Open ‘launch.json’

  3. Select the option to ‘Add Configuration’ at the bottom right of the screen

  4. Select the configuration for ‘Chrome: Launch’. The following default configuration will be added to launch.json

{
    "type": "chrome",
    "request": "launch",
    "name": "Launch Chrome",
    "url": "http://localhost:8080",
    "webRoot": "${workspaceFolder}",
}

Modify the url to point to the port where the application is being served. Also modify the webRoot to point to the public folder used to host static files.

{
    "url": "http://localhost:3000",
    "webRoot": "${workspaceFolder}/public",
}

In my setup I was unable to set breakpoints on JavaScript code inside index.html wrapped within <script> tags. I was able to debug .js files that were loaded into index.html.

Setup multi-targeted debugging

Setup a compound debug configuration by adding the following to ‘launch.json’

{
    "configurations": [
    ],
    "compounds": [
        {
            "name": "Server/Client",
            "configurations": ["Launch Chrome", "Docker: Attach to Node"]
        }
    ]
}

When the debugging session is started in VSCode both the configurations will be launched allowing to debug both the server and the client from VSCode

References

  1. What happens when a Node application is run in debug mode?
  2. Debugging Node Code in VS Code
  3. How to Debug a Node.js app in a Docker Container
  4. Live Debugging with Docker
  5. Restarting debug sessions automatically when source is edited
  6. Multi-target debugging in VSCode