Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Breakpoint is failing on nodemon + jest + docker / compose setup #1617

Closed
yuguan91 opened this issue Mar 29, 2023 · 5 comments · Fixed by #1632
Closed

Breakpoint is failing on nodemon + jest + docker / compose setup #1617

yuguan91 opened this issue Mar 29, 2023 · 5 comments · Fixed by #1632
Assignees
Labels
bug Issue identified by VS Code Team member as probable bug verified Verification succeeded
Milestone

Comments

@yuguan91
Copy link

yuguan91 commented Mar 29, 2023

Describe the bug
Breakpoints fails to work on nodemon + jest + docker. Sometimes I get a breakpoint at wrong line numbers in a readonly file with the same name, sometimes no breakpoints at all.

My local files are located in /User/me/some/path/app
Inside docker container, the files are located in root '/app'

I have a prelaunch task:

        {
            "label": "Start App",
            "type": "shell",
            "command": "./scripts/start-app.sh",
            "group": "test",
            "problemMatcher": [],
            "isBackground": true,
            "presentation": {
                "reveal": "always",
                "panel": "shared"
            }
        }

where ./scripts/start-app.sh essentially does:

docker-compose exec api \
    nodemon --no-lazy --legacy-watch --watch /app \
        --inspect-brk=app:9229 \
        /app/test/node_modules/jest/bin/jest.js --coverage \
            --config=/service/jest.config.json --runInBand

And an attach configuration:

{
            "type": "node",
            "request": "attach",
            "name": "App",
            "port": 9229,
            "restart": true,
            "preLaunchTask": "Start App",
            "localRoot": "${workspaceFolder}/app/",
            "remoteRoot": "/",
            "outFiles": [
                "${workspaceFolder}/app/**/*.js",
                "!**/node_modules/**"
            ],
            "skipFiles": [
                "<node_internals>/**/*.js",
                "${workspaceFolder}/**/node_modules/**/*.js"
            ],
            "pauseForSourceMap": true,
            "disableOptimisticBPs": true,
            "internalConsoleOptions": "neverOpen",
}

Debugger is able to attach to the process, because break point does hit the first line ofresolve() in path.js. But debugger statement doesn't work, nor does any break points.

I've got the vscode-js-debug nightly extension, and debugged it to a point where I think I found the cause:

When using jest, my code is getting compiled to add instrumentation. The source map somehow already has the original local path, so when _onScriptParsed calls rebaseRemoteToLocal() the following happens:

  public rebaseRemoteToLocal(remotePath: string) {
    // this.options === {
    //   removeRoot: '/',
    //   localRoot: '/User/me/some/path/app'
    // }
    // remotePath === '/User/me/some/path/app/file.js'

    if (!this.options.remoteRoot || !this.options.localRoot || !this.canMapPath(remotePath)) {
      return path.resolve(remotePath);
    }

    // we get here, and relativePath becomes 'User/me/some/path/app/file.js'
    const relativePath = properRelative(this.options.remoteRoot, remotePath);
    if (relativePath.startsWith('..')) {
      return '';
    }

    // we get here, and localPath becomes '/User/me/some/path/app/User/me/some/path/app/file.js'
    let localPath = properJoin(this.options.localRoot, relativePath);

    localPath = fixDriveLetter(localPath);
    this.logger.verbose(
      LogTag.RuntimeSourceMap,
      `Mapped remoteToLocal: ${remotePath} -> ${localPath}`,
    );
    return properResolve(localPath);
  }

I've added a branch statement in this function to check if remotePath already contains localRoot (and removeRoot is a substring of localRoot)

  public rebaseRemoteToLocal(remotePath: string) {
    if (!this.options.remoteRoot || !this.options.localRoot || !this.canMapPath(remotePath)) {
      return path.resolve(remotePath);
    }

    if (remotePath.includes(this.options.localRoot)) {
      // somehow the remote path is already available, don't rebase anymore
      return path.resolve(remotePath);
    }
    ...
  }

And that seemed to fix my issue.

To Reproduce
Steps to reproduce the behavior:

  1. You probably will need:
    jest: 26.4.2
  2. Create docker, compose, some js src and test
  3. Copy my launch and task configs
  4. Try set a break point

Log File
Will send logs to your email

VS Code Version:
Version: 1.76.2 (Universal)
Commit: ee2b180d582a7f601fa6ecfdad8d9fd269ab1884
Date: 2023-03-14T17:54:09.061Z (2 wks ago)
Electron: 19.1.11
Chromium: 102.0.5005.196
Node.js: 16.14.2
V8: 10.2.154.26-electron.0
OS: Darwin x64 22.3.0
Sandboxed: No

Additional Context:
I upgraded from 1.59 to 1.76, since debugger hasn't worked with our old setup after 1.59, until today I have the time for the upgrade. The regression might have happened anywhere in between.

@yuguan91 yuguan91 added the bug Issue identified by VS Code Team member as probable bug label Mar 29, 2023
@yuguan91
Copy link
Author

We are using docker-compose's volumes to mount local files to remote, so when we save to local file, the changes are reflected in the container, and that will trigger nodemon to restart our jest unit tests. The remote path might have been messed up by mounting the volumes.

@connor4312
Copy link
Member

Verification steps:

  1. Make a simple Jest package in a folder called jest-test https://jestjs.io/docs/getting-started

  2. Run in docker, example

     docker run -w /jest-test -v `pwd`:/jest-test -p 19229:19229 node:18-alpine --inspect-brk=0.0.0.0:19229 /jest-test/node_modules/jest/bin/jest.js --runInBand
    
  3. Create a launch config

     {
       "name": "Attach to Node",
       "port": 19229,
       "request": "attach",
       "skipFiles": [
         "<node_internals>/**"
       ],
       "continueOnAttach": true,
       "localRoot": "${workspaceFolder}/../",
       "remoteRoot": "/",
       "type": "node"
     }
  4. Verify you can set and hit a breakpoint

connor4312 added a commit that referenced this issue Apr 1, 2023
…child of remoteRoot

Fixes #1617

If the url in a sourcemap is relative, assume we've already mapped the
compiledPath, and don't map again.
@connor4312
Copy link
Member

This will be fixed in the nightly build on Monday after 5PM PST. Please let me know if it works for you.

@connor4312 connor4312 added this to the April 2023 milestone Apr 1, 2023
connor4312 added a commit that referenced this issue Apr 1, 2023
…child of remoteRoot

Fixes #1617

If the url in a sourcemap is relative, assume we've already mapped the
compiledPath, and don't map again.
connor4312 added a commit that referenced this issue Apr 1, 2023
…child of remoteRoot (#1632)

Fixes #1617

If the url in a sourcemap is relative, assume we've already mapped the
compiledPath, and don't map again.
@yuguan91
Copy link
Author

yuguan91 commented Apr 4, 2023

Confirmed on nightly, bp is working.

@eleanorjboyd eleanorjboyd added verified Verification succeeded author-verification-requested Issues potentially verifiable by issue author and removed author-verification-requested Issues potentially verifiable by issue author labels Apr 27, 2023
@eleanorjboyd
Copy link
Member

marking as verified based on @yuguan91's comment

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Issue identified by VS Code Team member as probable bug verified Verification succeeded
Projects
None yet
3 participants