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

'Step Into' steps into transpiled JavaScript when debugging TypeScript that uses async/await #115670

Closed
arsinclair opened this issue Feb 3, 2021 · 5 comments
Assignees
Labels
debug Debug viewlet, configurations, breakpoints, adapter issues upstream Issue identified as 'upstream' component related (exists outside of VS Code) upstream-issue-linked This is an upstream issue that has been reported upstream

Comments

@arsinclair
Copy link

arsinclair commented Feb 3, 2021

Essentially, this is very similar to #59920: when debugging a typescript script I step into an async function, it takes me to the transpiled javascript, instead of the first line of the function body. If I explicitly put a breakpoint at the first line of the function body, and hit continue several times, then I'm able to reach the breakpoint.

I was wondering why it happens, and there is no obvious reason: my source maps are present and recognised by the debugger; stepping into some non-async functions works fine. It has transpired that the moment it takes me to the transpiled js, there are a few more lines in the Call Stack above the transpiled code, but they are hidden by skipFiles. The actual place where debugger stops is /internal/async_hooks, first line of emitInitNative function.

I have found the following old bug report which seems to be related nodejs/node#15464, but the original issue is fixed.

I would expect the debugger not to stop at /internal/async_hooks because that's probably why it throws me back to the transpiled code. I'm ready to provide any information/logs about the issue, but unfortunately I can't share the reproduction code.

Here's how an example function looks like.

export const synchronize = async (details: SyncDetails): Promise<void> => {
    .... <function body>
    await runHook("onSynchronized", details.hooks, syncResult);
};

launch.json:

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "pwa-node",
      "request": "launch",
      "name": "Debug",
      "args": [
        "${workspaceFolder}/scripts/postinstall.ts"
      ],
      "runtimeArgs": [
        "--nolazy",
        "--require",
        "ts-node/register",
        "--require",
        "tsconfig-paths/register"
      ],
      "console": "integratedTerminal",
      "cwd": "${workspaceFolder}",
      "timeout": 30000,
      "sourceMaps": true,
      "resolveSourceMapLocations": null,
      "smartStep": true,
      "skipFiles": [
        "<node_internals>/**",
        "node_modules/**/*.js"
      ]
    }
  ]
}

Node version: 15.0.1
VSCode version: 1.52.1

  • VSCode Version:
  • OS Version:

Steps to Reproduce:

Does this issue occur when all extensions are disabled?: Yes/No

@connor4312
Copy link
Member

Can you share your tsconfig.json?

@arsinclair
Copy link
Author

My set-up is not a common one: I have two projects, project A and project B. Project B is a referenced package of project A and is located in node_modules. I've linked two projects using yarn link so instead of using a copy from node_modules, it creates a symlink to the Project B folder. Therefore I have two tsconfig.json to share:

Project A, tsconfig.json

{
  "extends": "@tsconfig/recommended/tsconfig.json",
  "ts-node": {
    "files": true
  },
  "compilerOptions": {
    "target": "ES2019",
    "moduleResolution": "node",
    "lib": ["DOM", "ESNext"],
    "resolveJsonModule": true,
    "allowSyntheticDefaultImports": true,
    "experimentalDecorators": true,
    "noEmitOnError": true,

    "preserveSymlinks": true,

    "noFallthroughCasesInSwitch": true,
    "noImplicitReturns": true,

    "inlineSourceMap": true,
    "inlineSources": true,
    // "sourceMap": true,

    "declaration": true,
    "declarationMap": true,

    "removeComments": true,
    "newLine": "lf",

    "jsx": "react",
    "baseUrl": ".",
    "paths": {
      "Common/*": ["src/common/*"],
      "Main/*": ["src/main/*"],
      "Renderer/*": ["src/renderer/*"],
      "Types/*": ["src/types/*"],
      "~/*": ["src/*"]
    }
  },
  "include": ["src/**/*"],
  "exclude": ["scripts/**/*"]
}

Project B, tsconfig.json

{
  "compilerOptions": {
    "lib": ["ESNext"],
    "module": "commonjs",
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "target": "es6",
    "resolveJsonModule": true,
    "noImplicitAny": true,
    "moduleResolution": "node",
    "skipLibCheck": true,
    "outDir": "dist",
    "baseUrl": ".",
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    // "inlineSourceMap": true,
    // "inlineSources": true,
    "paths": {
      "Modules/*": ["src/modules/*"],
      "Utils/*": ["src/utils/*"],
      "Types/*": ["src/types/*"],
      "Config/*": ["src/config/*"],
    },
    "plugins": [
      { "transform": "typescript-transform-paths" },
      { "transform": "typescript-transform-paths", "afterDeclarations": true }
    ]
  },
  "include": [
    "src/**/*"
  ]
}

You can see that in first config sourceMap: true is commented out and in the second config inlineSourceMap: true is commented out. I've experimented with those parameters to try different combinations and see if it helps, but no luck.

@connor4312
Copy link
Member

connor4312 commented Feb 4, 2021

One thing I'd recommend to to target es2017 or later in project B, if possible. Targeting es6 will downlevel async/await, which can cause the debugger to pause on sections of the code which don't have sourcemaps and cause us to fall back to showing the transpiled code.

@arsinclair
Copy link
Author

arsinclair commented Feb 5, 2021

@connor4312 targeting ES2019 in Project B has solved the issue with stepping through transpiled code. Thank you, it is good to know!

However, the issue of breaking on /internal/async_hooks's function emitInitNative still persists. Now it is masked by skipFiles so the debugger doesn't bring me to async_hooks.js code anymore, however it hits it multiple times, which makes me click Step Into on my function multiple times, it can be up to 10-15 times. Here's a GIF of how it looks:

Peek 2021-02-05 03-03

@connor4312
Copy link
Member

Thanks for the follow up. I don't reproduce this on Node 12, but I do on 15. There seems to be a related issue open on Node.js, and I have added additional information there: nodejs/node#36022. Subscribe to that issue for updates 🙂

@connor4312 connor4312 added debug Debug viewlet, configurations, breakpoints, adapter issues upstream Issue identified as 'upstream' component related (exists outside of VS Code) upstream-issue-linked This is an upstream issue that has been reported upstream labels Feb 6, 2021
@github-actions github-actions bot locked and limited conversation to collaborators Mar 23, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
debug Debug viewlet, configurations, breakpoints, adapter issues upstream Issue identified as 'upstream' component related (exists outside of VS Code) upstream-issue-linked This is an upstream issue that has been reported upstream
Projects
None yet
Development

No branches or pull requests

2 participants