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

Debugging in VS Code and Chrome not working with TypeScript #2897

Open
YoannBureau opened this issue Nov 5, 2018 · 30 comments
Open

Debugging in VS Code and Chrome not working with TypeScript #2897

YoannBureau opened this issue Nov 5, 2018 · 30 comments
Labels
needs team repro We acknowledged your report and will soon try to reproduce it scope: typescript

Comments

@YoannBureau
Copy link

Version

3.1.1

Reproduction link

https://github.com/YoannBureau/vuejs-vscode-ts-ko

Node and OS info

NPM 6.4.1

Steps to reproduce

  • npm install
  • in vs code, install "Debugger for Chrome" extension if not done yet
  • npm run serve
  • set a breakpoint in HelloWorld.vue line 43
  • start debug using "vuejs: chrome" debug config (FYI I reproduced the same steps as here: https://fr.vuejs.org/v2/cookbook/debugging-in-vscode.html )
  • click the button in the component

What is expected?

Breakpoint should be hit

What is actually happening?

Breakpoint is not hit


It's working great with Js, but ko with Ts

@YoannBureau
Copy link
Author

Any idea, friends?

@amsokol

This comment has been minimized.

@AidanGG
Copy link

AidanGG commented Dec 1, 2018

I was able to set breakpoints directly in Chrome by going to Sources, webpack://. and this would work, but is definitely suboptimal. Are there perhaps any better options?

@YoannBureau
Copy link
Author

Well, what we are looking for is setting breakpoints directly in vs code, not in Chrome. What @AidanGG did work but it's not practical at all.

@LinusBorg

This comment has been minimized.

@LinusBorg LinusBorg added scope: typescript needs team repro We acknowledged your report and will soon try to reproduce it labels Dec 4, 2018
@YoannBureau
Copy link
Author

Can the team reproduce the isssue? Might be cool to have this feature working :)

@SeanMBe
Copy link

SeanMBe commented Jan 26, 2019

Jetbrains is tracking this issue also reported for webstorm here: https://youtrack.jetbrains.com/issue/WEB-34557

Is there anything I can do to help resolve?

@ffxsam
Copy link
Contributor

ffxsam commented Jan 29, 2019

Just noticed this tonight when I was following the instructions on debugging using VS Code, which do not work for Vue TS projects.

@ffxsam
Copy link
Contributor

ffxsam commented Jan 29, 2019

This launch.json works for me:

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "chrome",
      "request": "launch",
      "name": "vuejs: chrome",
      "url": "http://localhost:8080",
      "webRoot": "${workspaceFolder}",
      "breakOnLoad": true,
      "sourceMaps": true,
      "disableNetworkCache": true,
      "sourceMapPathOverrides": {
        "webpack:///*": "${webRoot}/*",
        "webpack:///./*": "${webRoot}/*",
        "webpack:///src/*": "${webRoot}/src/*"
      }
    }
  ]
}

@jschoedt
Copy link

@ffxsam when you write "works" - are you able to set breakpoints in vue files? I am only able to debug ts files.

@ffxsam
Copy link
Contributor

ffxsam commented Feb 21, 2019

@jschoedt Yep, breakpoints in vue files works great. The only thing that doesn't seem to work with the debugger is when you hit async functions. Things really fall apart then.

@ayyron-dev
Copy link

Is this isolated to TypeScript? I am not using typescript and I've found that my breakpoints in async functions are hit but it falls apart when the first await is executed; the debugger gets lost and can't step past that line.

@rdhelms
Copy link

rdhelms commented Mar 18, 2020

Here's a slight variant to the example that @ffxsam provided. This configuration is working decently for us with Vue Cli 4.2.3 and TypeScript:

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "chrome",
            "request": "launch",
            "name": "vuejs: chrome",
            "url": "http://localhost:8080",
            "webRoot":"${workspaceFolder}",
            "breakOnLoad": true,
            "sourceMapPathOverrides": {
                "webpack:///./*": "${webRoot}/*"
            },
            "skipFiles": [
                "${workspaceFolder}/node_modules/**/*"
            ]
        }
    ]
}

So far we haven't seemed to need the other sourceMapPathOverrides, and adding the skipFiles seemed to help. I'd be interested to know if anyone else finds use cases for the other sourceMapPathOverrides.

I also want to reiterate the strangeness with trying to debug some await code. Sometimes it works, but other times VSCode totally won't allow setting a breakpoint on a line with await. Our current workaround is literally to write a non-async line of code above or below the await-ed line, and stick the breakpoint there. So there definitely still seems to be some room for improvement.

await someAsyncThing()  // Can't add breakpoint here
console.log('stop here')  // Can add breakpoint here

@geekox86
Copy link

Greetings all. I am using @vue/cli version 4.2.3 and breakpoints do not work in JetBrains IDE's when using TS + Vue SFC's.

We just want to know what is root of the issue so maybe we can help with workarounds?

@rdhelms
Copy link

rdhelms commented Apr 10, 2020

@geekox86 I'm not sure if anyone has a very clear understanding of the "root" of the issue except that it seems like varying the source map paths can make it better or worse.

But none of the configurations listed here seem to completely fix the problem. Even the example configuration that I posted above has not been working quite as smoothly as I initially thought. And even when I thought it was working well, it still was very broken when debugging async/await code.

I'm curious if anyone has tried debugging a Vue+TS project using the new JavaScript Debugger extension that VSCode mentioned in its March update

@geekox86
Copy link

geekox86 commented Apr 10, 2020

@rdhelms I just tried it on the mentioned new JS debugger and I can confirm that issue still exists. Debugging TS code however is much better however.

@zhaitianye
Copy link

Here's a slight variant to the example that @ffxsam provided. This configuration is working decently for us with Vue Cli 4.2.3 and TypeScript:

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "chrome",
            "request": "launch",
            "name": "vuejs: chrome",
            "url": "http://localhost:8080",
            "webRoot":"${workspaceFolder}",
            "breakOnLoad": true,
            "sourceMapPathOverrides": {
                "webpack:///./*": "${webRoot}/*"
            },
            "skipFiles": [
                "${workspaceFolder}/node_modules/**/*"
            ]
        }
    ]
}

So far we haven't seemed to need the other sourceMapPathOverrides, and adding the skipFiles seemed to help. I'd be interested to know if anyone else finds use cases for the other sourceMapPathOverrides.

I also want to reiterate the strangeness with trying to debug some await code. Sometimes it works, but other times VSCode totally won't allow setting a breakpoint on a line with await. Our current workaround is literally to write a non-async line of code above or below the await-ed line, and stick the breakpoint there. So there definitely still seems to be some room for improvement.

await someAsyncThing()  // Can't add breakpoint here
console.log('stop here')  // Can add breakpoint here

hello, 你好,在断点过程中,我遇到了同样的问题,请问有没有解决办法。

methods: {
    handleTest(){
      console.log(this) // VueComponent
    },
    async handleTest2(){
      console.log(this) // undefined
    }
  }

@rdhelms
Copy link

rdhelms commented May 6, 2020

@zhaitianye Still no solution that I'm aware of 🙁

@zhaitianye
Copy link

@rdhelms

methods: {
    handleTest(){
      console.log(this) // VueComponent
    },
    async handleTest2(){
      console.log(this)  // undefined
      let that = this
      console.log(that) // VueComponent
    }
  }

This is the temporary solution I know of. IN Google Chrome Debug

@Moseyza
Copy link

Moseyza commented Aug 20, 2020

using vue/cli 4.4.6 no solution works for me!
is there any solution for enable breakpoints?

@rdhelms
Copy link

rdhelms commented Aug 20, 2020

This is what we currently use. It seems to allow setting breakpoints with mostly successful results. Trying to use VS Code's "step over" functionality pretty much always ends up either jumping to the top of the component export default class SomeComponent... or in some js/app.js asyncGeneratorStep code. The breakpoints themselves do seem to generally work, though sometimes it works better to put the breakpoint on a line either above or below any actual async/await logic rather than directly on it.

Also note that in order for this to work, npm run serve has to be run separately prior to starting this debug program.

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "pwa-chrome",
            "request": "launch",
            "name": "vuejs: chrome",
            "url": "http://localhost:8080",
            "webRoot":"${workspaceFolder}",
            "sourceMapPathOverrides": {
                "webpack:///./*": "${webRoot}/*"
            },
            "skipFiles": [
                "${workspaceFolder}/node_modules/**/*"
            ]
        }
    ]
}

Incidentally, I'm not actually sure if the webRoot or sourceMapPathOverrides properties are necessary, but removing skipFiles sometimes lands me in some regenerator-runtime node_module.

@lmexo
Copy link

lmexo commented Nov 19, 2020

Before you read: This will not provide any solution but maybe helps finding a direction to solve the problem.

I also spent a lot of time in this problem but to me it actually does not seem to be a problem with vue-cli or the source-map-path-mapping, but the vue-loader (currently using with vue-loader 16.0.0-rc.2). According to vscode-chrome-debug's trace, the sourcemaps are found and pointing as expected, so the source files should be resolved. Looking in Chrome, the files with the hash-information do contain the code i do not care for debugging:
image

The problem is, however, when i place a breakpoint in vscode in foobar.ts, it will not be hit. Instead, when placing the breakpoint in chrome (also foobar.ts) it will be hit (in chrome, but vscode also stops).

As far as i know, chrome reconstructs foobar.ts' sources from the source-map but does not really know the original file. Looking at vscode-chrome-debug's trace again, it seems chrome itself cannot resolve the position of the breakpoint when it is requested by vscode. I don't know much about chrome's devtool-api, but the vscode-chrome-debug-trace look a bit like (working example, e.g when not using typescript but javascript or a typescript file not loaded through the vue-loader)
vscode: place breakpoint near line 2, column 0 in file main.ts
chrome: breakpoint placed in line 2, column 5 in file main.ts
vscode: get neares breakpoints
chrome: in line 2 you may set breakpoint in column 5, 12, ...

But when placing breakpoints in typescript referenced from vue-file it is more like
vscode: place breakpoint near line 2, column 0 in file foobar.ts
chrome: ... ... I will let you know when i stop somehere in the bundle.js.

Finally i would assume that the reverse-lookup in the source-map does result in the correct code-segment (if one can say it like that, i am not that deep into the topic of source-maps)

But again: this only happens, when using typescript in vue-components, javascript does not cause any problem.

@lmeysel
Copy link

lmeysel commented Nov 19, 2020

I stepped a bit further now, looking again in the logs of the vscode-chrome-debugger trace, and found something confusing:
image

There are two sourcemap-tags for app.ts (which is referenced from app.vue), saying "SourceMap: mapping .../app.ts". The order of the sourcemap-tags roughly matches the order of the sources as provided in the source-map. So i changed the corresponding (second) file in the source-map and suddenly the vscode-debugger works as intended. It "feels" like the second mapping overrides the first one, thus the breakpoint set in the first (the real app.ts) will be resolved to the "second" app.ts (which in fact is "app.ts?xxxx". But since the second one is not found by vscode, it kind of falls back to the bundle.js. Voilà.

Now the question is how to solve it. But if I am on the right path this issue is not part of vue-cli (it also appears when using laravel-mix and probably also when only using the vue-loader with webpack only).

@geekox86
Copy link

geekox86 commented Jan 1, 2021

Greetings all. Any progress on this long standing issue?
Is any body able to debug Vue SFC files with TypeScript using Vue CLI 4.5.9?

@andrewmackrodt
Copy link

andrewmackrodt commented Mar 2, 2021

I've spent quite a while trying to get IDE debugger support working correctly in Vue 2 and Vue 3 apps and have found some settings that seem to work, at least in a simple quick start style monorepo application. I'm using a manually created webpack configuration but (this also works with vue-cli, see example repo https://github.com/andrewmackrodt/vue3-ide-breakpoint-test) hopefully my findings are useful to someone:

vue-loader >= 16

TS source maps compiled with vue-loader >= 16 are generated using @vue/compiler-sfc; the behaviour has changed from previous versions where newlines up until <script lang="ts"> are not respected, this results in the IDE generating breakpoints at a position too late, e.g. if <template> is lines 1-5 and <script lang="ts"> starts at line 7, all breakpoints are off by 6 lines.

I've provided an example of such compilation below, please note that these screenshots were taken using vue 2 (vue-loader 15) and vue 3 (vue-loader 16) respectively so there are some minor changes between the files:

vue-2
vue-3

I have a PR open in vue-loader to specify that padding is required but it has not been looked at yet. In the meantime this can be achieved by overriding the parse method in @vue/compiler-sfc via webpack.config.js, e.g.

const CompilerSfc = require('@vue/compiler-sfc')
const parse = CompilerSfc.parse
CompilerSfc.parse = (source, options) => {
  return parse(source, Object.assign({ pad: true }, options))
}

vue 2 specific notes
Setting devtool: 'eval-source-map' seems to work better than other options, at least with IntelliJ IDEs; other settings result in step over acting more like continue.

vue 3 specific notes
Setting devtool: 'source-map' seems to work better than other options, at least with IntelliJ IDEs; other settings result in step over acting more like continue. I don't know why this differs from my experience with vue 2, perhaps it's related to my plug-in setup in my webpack config.

vue 3 vs code notes (maybe applicable to vue 2)
Unlike IntelliJ IDEs, VS Code seems to have trouble finding the correct Component.vue?hash file when setting breakpoints in VS Code and starting a Chrome debug session, at least in my quick start monorepo project. To work around this, we need to instruct webpack to generate a filename without the hash part of the filename for the TypeScript element of the component. This is possible by providing a function to output.devtoolModuleFilenameTemplate in webpack.config.js, e.g.

  output: {
    path: path.join(path.resolve(`${__dirname}/../..`), 'build/public'),
    publicPath: '/',
    filename: 'bundles/[name]' + ( ! isDev ? '.[chunkhash:7]' : '') + '.js',
    chunkFilename: 'bundles/[name]' + ( ! isDev ? '.[chunkhash:7]' : '') + '.js',
    devtoolModuleFilenameTemplate: info => {
      if (info.allLoaders === '') {
        // when allLoaders is an empty string the file is the original source
        // file and will be prefixed with src:// to provide separation from
        // modules transpiled via webpack
        const filenameParts = ['src://']
        if (info.namespace) {
          filenameParts.push(info.namespace + '/')
        }
        filenameParts.push(info.resourcePath.replace(/^\.\//, ''))
        return filenameParts.join('')
      } else {
        // otherwise we have a webpack module
        const filenameParts = ['webpack://']
        if (info.namespace) {
          filenameParts.push(info.namespace + '/')
        }
        filenameParts.push(info.resourcePath.replace(/^\.\//, ''))
        const isVueScript = info.resourcePath.match(/\.vue$/) &&
            info.query.match(/\btype=script\b/) &&
            ! info.allLoaders.match(/\bts-loader\b/)
        if ( ! isVueScript) {
          filenameParts.push('?' + info.hash)
        }
        return filenameParts.join('')
      }
    },
  },

This assumes that there is a maximum of one <script> element in the .vue SFC.

@fearnycompknowhow
Copy link

I'm sorry if this seems like it's just a shameless plug, but I actually just wrote a blog about this.

My method is not an official fix per-se, although it will fix the problem. It's more of a patch that you apply at the end of the build process by doing some manual Source Map manipulation.

I can confirm that it will work with non class-based TypeScript Single File Components, however, I haven't tested it with class-based TypeScript SFCs.

The blog was written based on Vue 3, but you probably could adapt it to work with Vue 2.

@andrewmackrodt seems to have a pretty good solution above as well, so definitely take a look at his post.

@KondakovVE
Copy link

work for me.

"version": "0.2.0",
  "configurations": [
    {
      "type": "chrome",
      "request": "launch",
      "name": "Frontend",
      "url": "http://localhost:8080",
      "webRoot": "${workspaceFolder}/frontend/src", //<-this is local path to sources from workspace folder. src here important 
      "breakOnLoad": true,
      "disableNetworkCache": true,
      "sourceMaps": true,
      "sourceMapPathOverrides": {
        "webpack:///src/*": "${webRoot}/*",
        "webpack:///./src/*": "${webRoot}/*" //<- src here is the same folder. 
      },
      "skipFiles": ["${workspaceFolder}/frontend/node_modules/**/*"]
    }
  ]

@J-Rojas
Copy link

J-Rojas commented May 22, 2022

@fearnycompknowhow your solution worked for me on Vue2 and Chrome dev tools but I had to remove the indexOfScriptTag adjustment for the source file lines to correctly match in my SFC files with Typescript. Thanks!

@Shujee
Copy link

Shujee commented May 30, 2022

@fearnycompknowhow: I have got mixed results with your solution when using Vue 3 SFCs. I'm using TypeScript with <script setup> syntax. Problem I'm facing is that I need to add some offset to indexOfScriptTag variable (e.g. line: originalLine + indexOfScriptTag - 5). That would be okay if there were a single offset value, but that's not the case. Different vue files work with different offset values; otherwise actual code execution goes several lines ahead/behind when a breakpoints get hit.

I haven't been able to identify any relation between the offset value and the vue file contents so far.

@caiqichang
Copy link

+1, and how to solve it now? 😥

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs team repro We acknowledged your report and will soon try to reproduce it scope: typescript
Projects
None yet
Development

No branches or pull requests