7

I'm attempting to setup a debugger in VsCode using the attach mode on a Typescript codebase running in a Docker container. When I run my docker container and attach the debugger via VsCode, I'm able to hit breakpoints, but they always end up on the compiled Javascript code instead of the Typescript code.

enter image description here

As you can see from the image, the code is a simple log statement inside an infinite loop.

index.ts

console.log('Hello world');

while(true) {
  console.log('a')
}

Before moving to the setup with Docker, I checked the docs and tried the debugger locally and that had no problems hitting breakpoints on Typescript files. Here is more info on the setup:

launch.json

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "attach",
      "name": "Launch Program",
      "port": 9229,
      "restart": true,
      "address": "localhost",
      "remoteRoot": "./",
      "localRoot": "${workspaceFolder}",
      "outFiles": ["${workspaceFolder}/dist/**/*.js"],
      "sourceMaps": true
    }
  ]
}

docker-compose.yml

version: '3.8'
services:
  nodeserver:
    command: nodemon --inspect=0.0.0.0:9229 ./dist/index.js
    build:
      context: ./
      dockerfile: ./build/Dockerfile
    ports:
      - '3000:3000'
      - '9229:9229'

Dockerfile

FROM node:15-alpine3.11 as production

WORKDIR /opt/project

COPY package.json .
RUN yarn global add typescript
RUN yarn global add nodemon
RUN yarn install

COPY src src
COPY tsconfig.json .

RUN tsc

tsconfig.json

{
  "compilerOptions": {
    "target": "es5",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
    "module": "commonjs",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
    "sourceMap": true,                     /* Generates corresponding '.map' file. */
    "outDir": "./dist",                        /* Redirect output structure to the directory. */
    "strict": true,                           /* Enable all strict type-checking options. */
    "esModuleInterop": true,                  /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
    "skipLibCheck": true,                     /* Skip type checking of declaration files. */
    "forceConsistentCasingInFileNames": true  /* Disallow inconsistently-cased references to the same file. */
  }
}

I've tried multiple setups using nodemon and regular node, but none of these setups have been able to hit breakpoints and point back the result onto the Typescript files. Is it possible to do this while attaching to a process?

4 Answers 4

6

So after coming back to this issue I managed to fix it. Here are some important things to check.

  1. Check if the port and address actually connect when attaching. A message saying Debugger connected should appear in your console if this works.

If your debugger connects, but your breakpoints are unbound or you are seeing errors in your debugger terminal, try these steps:

  1. Make sure sourceMaps is set to true in your launch.json and sourceMap is set to true in your tsconfig.json. This generates the required files to hit breakpoints on TS files and tells your debugger to use them.
  2. If you are using a specific workspace in your docker, (e.g. WORKSPACE /opt/project) make sure your remoteRoot in your launch.json is set to that value. If you're not using any workspace, make sure the value is set to /, I ran into some issue when using ./.
  3. Add the resolveSourceMapLocations property to your launch.json this should help your debugger locate your .map.js files if it has trouble finding it. link
  4. If your project isn't contained in the root folder, make sure the localRoot property points to the directory containing your code.
  5. If all these steps fail, try seeing if your are on VsCode v16.0 or higher, at the time of writing this there is a known issue with the debugger of VsCode in v16 and up. These settings work on v15.8.2

These were the steps that I had to go through in order to get this to work. Here is the launch.json that I use now.

{
  // Use IntelliSense to learn about possible attributes.
  // Hover to view descriptions of existing attributes.
  // For more information, visit: https://go.microsoft.com/fwlink/? 
     linkid=830387
  
 "version": "0.2.0",
 "configurations": [
 {
  "type": "node",
  "request": "attach",
  "name": "Debug: App",
  "remoteRoot": "/opt/project/",
  "localRoot": "${workspaceFolder}",
  "port": 9229,
  "restart": true,
  "sourceMaps": true,
  "resolveSourceMapLocations": ["${workspaceFolder}/**", "!**/node_modules/**"]

  // Only enable for debug purposes.
  // "trace": true
  }
 ]
}
Sign up to request clarification or add additional context in comments.

Comments

0

In the end, TypeScript is compiled into JavaScript on process level and when using regular debugger remotely, it might not properly identify which was the original format of the source.

This might be duplicate of Debug in VS Code a Node Typescript app running in Docker

You should use extension "Remote development" which is developed by Microsoft partially for this purpose, to get better experience on mapping the source for container process.

Comments

0

Ran into this issue too. Running a node server in a docker container trying to attach a debugger. Implemented all of the solutions mentioned in this post and other ones with no success.

The actual issue was that we were using ts-node-dev to run our server with hot reloading. It seems like it will copy the compiled ts files into some virtual space (not present on disk so you can't even find the file locally), so the vscode breakpoints will actually be set on these files since the file path is the same.

The solution was to move off of this, so moving to nodemon fixed it.

Comments

0

For me the issue was that I had to set the sourceRoot to ./ in tsconfig.json since the sources path was incorrectly set, where it didn't even have a path.

I would suggest checking the generated .map.js and check what the sources path is and see what the sourceRoot is set to when generated.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.