microsoft / vscode

Visual Studio Code
https://code.visualstudio.com
MIT License
163.4k stars 28.95k forks source link

Breakpoints in Azure Functions Typescript project shown as unbound but are hit in the mjs file anyways #198215

Closed muecke36 closed 7 months ago

muecke36 commented 11 months ago

Type: Bug

Steps to reproduce:

  1. Open the project in vscode
  2. Build the project
  3. Run func host start to launch the local azure function host
  4. Launch "Attach by process ID" launch configuration to start the debugger
  5. Node shows "Debugger attached" and debugging session is started
  6. Set a breakpoint in any mts file
  7. Breakpoint is shown as unbound
  8. Start the corresponding function
  9. Breakpoint is hit and vscode shows the corresponsing mjs file with the debug cursor at the correct position

We restructured the project and now any breakpoint set in an mts file is shown as unbound. However the breakpoint is set in the corresponding mjs file successfully and as soon as the program gets to the breakpoint it stops and vscode shows the mjs file with the debug cursor at the correct line. This is the output of the breakpoint trouble shooter:

✅ This breakpoint was initially set in:

D:\git\PlainStaff\API\src\functions\core\checkStatus\index.mts line 13 column 1

✅ In the runtime, the breakpoint was set in:

file:///d:/git/plainstaff/api/dist/functions/core/checkstatus/index.mjs($ line 19 column 5 via this regex

file:///d:/git/plainstaff/api/src/functions/core/checkstatus/index.mts($ line 13 column 1 via this regex

❓ We sent the breakpoint, but it didn't bind to any locations. If this is unexpected:
Make sure that your program is loading or running this script. You can add a debugger; statement to check this: your program will pause when it hits it.
If your breakpoint is set in certain places, such as on the last empty line of a file, the runtime might not be able to find anywhere to place it.
Unless you [run with --nolazy](https://code.visualstudio.com/docs/nodejs/nodejs-debugging#_breakpoint-validation), Node.js might not resolve breakpoints for code it hasn't parsed yet.
If necessary, make sure your compiled files are up-to-date with your source files.

This is the launch configuration:

{
      "name": "Attach by Process ID",
      "processId": "${command:PickProcess}",
      "request": "attach",
      "skipFiles": [
        "<node_internals>/**"
      ],
      "type": "node",
      "trace": true,
      "outFiles": ["${workspaceFolder}/dist/**/*.mjs"],
}

This is the debug trace:

vscode-debugadapter-11e222f7.json.gz

Tested with newest insider build of vscode and with deactivated extensions.

Node Version: 18.17.1 Typescript Version: 5.2.2

It seems like the breakpoint is successfully set but vscode cannot link it back to the source? Any hint for further digging highly appreciated! ❤️

VS Code version: Code - Insiders 1.85.0-insider (345c8d0927402d41f42402411d856eeec4013e5e, 2023-11-13T05:39:23.476Z) OS version: Windows_NT x64 10.0.22635 Modes:

System Info |Item|Value| |---|---| |CPUs|Intel(R) Core(TM) i7-10700K CPU @ 3.80GHz (16 x 3792)| |GPU Status|2d_canvas: enabled
canvas_oop_rasterization: enabled_on
direct_rendering_display_compositor: disabled_off_ok
gpu_compositing: enabled
multiple_raster_threads: enabled_on
opengl: enabled_on
rasterization: enabled
raw_draw: disabled_off_ok
video_decode: enabled
video_encode: enabled
vulkan: disabled_off
webgl: enabled
webgl2: enabled
webgpu: enabled| |Load (avg)|undefined| |Memory (System)|31.84GB (17.03GB free)| |Process Argv|--disable-extensions . --crash-reporter-id 413bff9f-cc8a-4f74-acbf-e5f859b987a3| |Screen Reader|no| |VM|0%|
Extensions disabled
A/B Experiments ``` vsliv695:30137379 vsins829:30139715 vsliv368:30146709 vsreu685:30147344 python383cf:30185419 vspor879:30202332 vspor708:30202333 vspor363:30204092 vslsvsres303:30308271 pythontb:30258533 pythonptprofiler:30281269 vshan820:30294714 vscod805:30301674 bridge0708:30335490 bridge0723:30353136 vsaa593cf:30376535 pythonvs932:30404738 py29gd2263:30784851 vscaat:30438846 vsclangdf:30492506 c4g48928:30535728 dsvsc012:30540252 pynewext54:30618038 showlangstatbar:30737417 pythonfmttext:30716741 fixshowwlkth:30771523 showindicator:30805243 pythongtdpath:30726887 i26e3531:30792625 welcomedialog:30812478 pythonnosmt12:30779711 pythonidxpt:30768918 pythonnoceb:30776497 asynctok:30869155 dsvsc013:30777762 dsvsc014:30777825 pythonmhint1:30859868 dsvsc015:30821418 pythontestfixt:30866404 pythonregdiag2:30871582 pyreplss1:30879911 pythonmypyd1:30859725 pythoncet0:30859736 pythontbext0:30879054 accentitlementst:30870582 dsvsc016:30879898 dsvsc017:30880771 dsvsc018:30880772 aa_t_chat:30882232 ```
connor4312 commented 11 months ago

What is the build process you use to convert the mts file to mjs?

The message is pretty descriptive about what's going on; the breakpoint mapped to a location (in this case a different column) that didn't exist in your sourcemap. This could also be caused by tools that transform your JavaScript code without updating the corresponding sourcemaps.

muecke36 commented 11 months ago

We use gulp for the build. It's pretty straight forward. The only transformations happen before the transpiling. Nothing is changed afterwards besides moving the transpiled files 2 levels up (which should'nt be a problem, right?). Also the position of the breakpoint in the mjs file and in the mts file that the trouble shooter shows are correct and contain the same code.

This is the part of the gulp pipeline that's responsible for the build:

gulp
    .src('src/**/*.mts', { base: 'src', sourceMap: true })
    .pipe(
      changed(`dist`, {
        transformPath: (newPath) => {
          /**
           * Only process changed files
           */
          const result =
            path.join(
              path
                .dirname(newPath)
                .replace(path.join('functions', 'config'), '')
                .replace(path.join('functions', 'automation'), '')
                .replace(path.join('functions', 'core'), '')
                .replace(path.join('functions', 'email'), '')
                .replace(path.join('functions', 'extensions'), '')
                .replace(path.join('functions', 'management'), '')
                .replace(path.join('functions', 'payment'), '')
                .replace(path.join('functions', 'public'), ''),
              path.basename(newPath, '.mts')
            ) + '.mjs';

          return result;
        },
      })
    )
    .pipe(
      tap(function (file) {
        /**
         * Replace @plainstaff/... imports with relative paths
         */
        if (file.path?.includes('testdata') || file.path?.includes('functions')) {
          const result = file.contents.toString().split('@plainstaff/lib').join('../lib/index.mjs').split('@plainstaff/testdata').join('../testdata/index.mjs');
          file.contents = Buffer.from(result);
        }
      })
    )
    .pipe(sourcemaps.init())
    .pipe(ts.createProject(tsConfigFile, tsConfig)())
    .pipe(
      sourcemaps.mapSources(function (sourcePath, file) {
        // source paths are prefixed with '../../src/'
        return '../../src/' + sourcePath;
      })
    )
    .pipe(
      sourcemaps.write('.', {
        includeContent: false,
      })
    )
    .pipe(
      rename(function (file) {
        /**
         * Move all functions 2 directories up so that they are under dist/
         * so that the local function host can find them
         */
        file.dirname = file.dirname
          .replace(path.join('functions', 'config'), '')
          .replace(path.join('functions', 'automation'), '')
          .replace(path.join('functions', 'core'), '')
          .replace(path.join('functions', 'email'), '')
          .replace(path.join('functions', 'extensions'), '')
          .replace(path.join('functions', 'management'), '')
          .replace(path.join('functions', 'payment'), '')
          .replace(path.join('functions', 'public'), '');
      })
    )
    .pipe(gulp.dest('dist'));

And this is our tsconfig:

tsconfig-base.json

{
  "compilerOptions": {
    "noEmit": true,
    "allowImportingTsExtensions": false,
    "allowArbitraryExtensions": false,
    "verbatimModuleSyntax": true,
    "isolatedModules": true,
    "noImplicitAny": false,
    "strict": true,
    "noImplicitThis": false,
    "esModuleInterop": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "strictPropertyInitialization": false,
    "strictNullChecks": false,
    "preserveConstEnums": true,
    "allowJs": true,
    "resolveJsonModule": true,
    "skipLibCheck": true,
  },
  "exclude": [
    "./dist/**/*",
    "./node_modules/**/*",
    "./terraform/**/*",
  ]
}

tsconfig-dev.json

{
  "extends": "./tsconfig-base.json",
  "compilerOptions": {
    "module": "NodeNext",
    "target": "ESNext",
    "moduleResolution": "NodeNext",
    "removeComments": false,
    "sourceMap": true,
    "outDir": "./dist",
    "baseUrl": "./src",
    "declaration": true,
    "paths": {
      "@plainstaff/lib": [
        "lib/index.mts"
      ],
      "@plainstaff/testdata": [
        "testdata/index.mts"
      ],
      "@plainstaff/core": [
        "functions/core/core.mts"
      ],
      "@plainstaff/config": [
        "functions/config/config.mts"
      ],
      "@plainstaff/automation": [
        "functions/automation/automation.mts"
      ],
      "@plainstaff/email": [
        "functions/email/email.mts"
      ],
      "@plainstaff/extensions": [
        "functions/extensions/extensions.mts"
      ],
      "@plainstaff/management": [
        "functions/management/management.mts"
      ],
      "@plainstaff/payment": [
        "functions/payment/payment.mts"
      ],
      "@plainstaff/public": [
        "functions/public/public.mts"
      ]
    }
  },
  "exclude": [
    "./scripts/**.*"
  ]
}
vscodenpa commented 7 months ago

Hey @connor4312, this issue might need further attention.

@muecke36, you can help us out by closing this issue if the problem no longer exists, or adding more information.

vscodenpa commented 7 months ago

This issue has been closed automatically because it needs more information and has not had recent activity. See also our issue reporting guidelines.

Happy Coding!