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 vite+vue+typescript using HMR is broken. Breakpoint on incorrect line numbers #33

Closed
7 tasks done
hspaay opened this issue Dec 1, 2021 · 35 comments
Closed
7 tasks done

Comments

@hspaay
Copy link

hspaay commented Dec 1, 2021

Describe the bug

Trying to debug a vite+vue+ts app doesn't work for me. As soon as HMR runs the vscode debugger no longer stops on breakpoints. Possible the sourcemap gets out of sync.

In addition, chrome devtools doesn't show the source code but the hard to read minified code.

Similar bugs:

  1. Line numbers in TypeScript broken for Chrome/VSCode debugging vite#5834 although this report mentions that "the application does indeed break at the expected moment, and both Chrome Debugger and VSCode highlight the same (correct) lines", which is different behavior than mentioned in this report.

  2. [@vitejs/plugin-react] VS Code Breakpoints do not get hit after first fast refresh in plugin-react in new project vite-plugin-react#23 might be the same issue but uses react. It does mention that a browser refresh fixes it, but does not mention the problem that setting breakpoints elsewhere in the code is no longer always possible.

The issue at hand seems that after HMR the sourcemaps get messed up. I suspect that the issue goes deeper than that as I have a more complex app where the source map remains incorrect even after clearing the cache. Anyway lets fix get the simple case addressed.

Reproduction

  1. Create a new vite app as follows

yarn create @vitejs/app; select vue as framework and vue-ts as the variant

  1. Build and run the dev server:

yarn
yarn dev

  1. start vscode (I'm using 1.62.3) and add the project folder to the workspace
  2. configure the launcher for chrome - run - add configuration - chrome; change the url port to 3000
  3. Start debugging. This should launch chrome displaying the vite demo app
  4. Open src/components/HelloWorld.vue in vscode and set a breakpoint on line 29, eg the button that has count++
  5. Click on the button: -> result vscode stops at the breakpoint as expected
  6. Edit the line to increment count by two, eg count+=2. Save
  7. Click on the button again
    Expected behavior: vscode stops at the breakpoint
    Actual behavior: breakpoint is ignored

After reloading the browser (F5) the breakpoint works again in this simple example until the code changes.

To spice it up a bit, replace the line with count++ to invoke a function 'incrementCount as follows:

  <button type="button" @click="() => incrementCount()">count is: {{ count }}</button>

and add this function in the script section:

const incrementCount = () => {
  count.value += 22
}

Repeat the test, this time setting the breakpoint in the function.-> this works as expected

Now try to set the breakpoint on the line with the button click. vscode will add a breakpoint in HelloWorld.vue?import=&t=1638336354075 (or something like it).

Hit the count button again... => expected behavior, the debugger stops. Actual behavior: the debugger does not stop.
Hit F5 in the browser. => expected behavior, the browser refreshes and shows the app. Actual behavior, the debugger stops somewhere randomly.

System Info

System:
    OS: Linux 5.13 Ubuntu 21.10 21.10 (Impish Indri)
    CPU: (4) x64 Intel(R) Core(TM) i5-4570S CPU @ 2.90GHz
    Memory: 5.43 GB / 23.32 GB
    Container: Yes
    Shell: 5.1.8 - /bin/bash
  Browsers:
    Chrome: 94.0.4606.61
    Firefox: 94.0
  npmPackages:
    @vitejs/plugin-vue: ^1.9.0 => 1.10.1 
    vite: ^2.5.10 => 2.6.14

Used Package Manager

yarn

Logs

No response

Validations

@martonx
Copy link

martonx commented Dec 19, 2021

This is a very serious issue! It is not jus TS, but for JS also.
My Vite + Vue + Js project is completly undebuggable.

@hspaay
Copy link
Author

hspaay commented Jan 6, 2022

Update: In my case this is only a problem for Single File Components. Debugging in typescript files seems to have correct line numbers. It does suggest that the problem is in sourcemap generation for SFCs.
Is there a way to get some more eyes on this?

@qq1063823095
Copy link

me too,I wonder how soon the author team can solve

@ngjermundshaug
Copy link

Started playing around with Vite+Vue tonight - and came across this error. I just don't get it - how can anyone use Vite when it's impossible to attach a debugger (Chrome // VSCode)....? This seems like a critical show stopper bug issue to me. Hope it gets fixed soon. Will have to revert to Webpack for now.

@hspaay
Copy link
Author

hspaay commented Feb 8, 2022

@ngjermundshaug yes indeed, it leads me to think that it either isn't used a lot or only hits a few people.
A long shot but maybe @yyx990803 can help to give it the attention it deserves.

@m430
Copy link

m430 commented Feb 21, 2022

me too, I can't debugging in chrome dev tool. It's a serious bug.

@Cmen117696
Copy link

Cmen117696 commented Feb 23, 2022

Got same issue with vite + typescript + react + mobx, but only happened in some ts file.

@libgcc
Copy link

libgcc commented Apr 23, 2022

can't believe this bug has been hanging for nearly half years and nothing changed
is vite just a toy or something

@hspaay
Copy link
Author

hspaay commented Apr 24, 2022

Agreed, it is unfortunate as apart from debugging not working I love vite.

Maybe it is time to look at alternatives. Has anyone tried snowpack? https://github.com/FredKSchott/snowpack, or maybe something else?
Update: 2022-05-06: snowpack is no longer updated and now recommends to use vite.

@byronwall
Copy link

I too am affected by this issue. I walked through the sequence below while playing around with this problem today. I was working on private code but suspect the same holds on a simpler repo.

Specific test:

  1. Baseline file = no changes - set a breakpoint at line 70 -- that line is just a console.log("test") -- this is a Typescript + React functional component = TSX file -- the breakpoint is in the middle of the function.
  2. Trigger the break point, all is good
  3. Add a single line of code at line 71 (just copy the console.log() from line 70), save the file, let the HMR trigger, breakpoint triggers -- breakpoint is still at line 70
  4. VS Code opens the ?import file which is the Vite processed version of the raw source
  5. The breakpoint triggers at line 71 in the ?import file. This is a completely different spot than intended since the file has been transformed.
  6. Remove the added line at 71, the file is now the exact same as before -- breakpoint is still at line 70 in the source file
  7. Save and trigger the breakpoint
  8. VS Code opens the ?import version of the file with the breakpoint at line 70 -- this is still nowhere near the intended spot since the ?import version is processed (not raw source)

So, between steps 1 and 9, the source code is the exact same, but the resulting breakpoint trigger location has changed when VS Code triggers. I don't know the internals well enough, but it seems that Vite is capable of handling the mapping correctly on first load, but then something changes post HMR. In particular, the thing that changes is independent of the actual source since my source files are identical at start and end.

I'm purely guessing, but it seems that the source map is missing the last hop to get from the ?import version of the page back to the raw source. This is my hunch since the triggered breakpoint is at the correct line in the wrong file. Further, it seems that the mapping is correct up until the HMR transform takes place.

If there are any pointers on how to debug these various steps, I'd give it a whirl. Unfortunately, I don't know the debugging process or source maps well enough to reason it out otherwise. That is, I'd love to help, but it's not clear how.

@hspaay
Copy link
Author

hspaay commented May 7, 2022

Based on issue vitejs/vite#673, it seems that disabling HMR works around the issue.
In vite.config.ts:

export default defineConfig({
  server: {
    hmr: false
  },
  plugins: [
...

It looks like the choice is to have HMR or debugging, you cannot have both.

If you don't mind restarting the dev server after each edit, this might be a viable (although somewhat tedious) workaround.

@hspaay hspaay changed the title Debugging vite+vue+typescript is broken using vscode (and webstorm). Breakpoint on incorrect line numbers Debugging vite+vue+typescript using HMR is broken. Breakpoint on incorrect line numbers May 7, 2022
@ngjermundshaug
Copy link

I made an attempt at upgrading from vue2 to vue3+vite a few days ago. Debugging worked fine for a few hours - until it suddenly didn't. Haven't been able to quite pinpoint what causes it yet.

BUT I have been able to make it work in Firefox (with HMR) by:

  1. Add a console.log statement somewhere in the vue file you want to debug
  2. Goto Console in Vue - click on the Filename:line that logged. This will open the correct source file that logged (Component.vue?t=123123423423)
  3. Attach debugger on given line

You can also press Ctrl-P in Debugger window in Firefox and open the component/file there - but you'll see several files (same name, different url) but make sure you take the cachebusted version (the one with ?t=123123123123).

@abdulghanitech
Copy link

I'm having same problem with vite. Not able to debug. :(

@ThePainnn
Copy link

ThePainnn commented Jul 19, 2022

I have the same issue (breakpoints are off by 10-20 lines depending on the file). It's not happening on all the files which is super strange. I'm trying to find a pattern.

Disabling HRM does not solve anything, but disabling sourcemaps is the only way I can debug something.

@ThePainnn
Copy link

ThePainnn commented Jul 20, 2022

Update on my bug. I've analyze the sourcemaps for a simple file (http://sokra.github.io/source-map-visualization/#custom is a very awesome tool). Every file containing an import of react has bad sourcemaps, without react it's fine. Those file contains generated code to enable HMR:

let prevRefreshReg;
let prevRefreshSig;

if (import.meta.hot) {
  if (!window.__vite_plugin_react_preamble_installed__) {
    throw new Error("@vitejs/plugin-react can't detect preamble. Something is wrong. " + "See https://github.com/vitejs/vite-plugin-react/pull/11#discussion_r430879201");
  }

  prevRefreshReg = window.$RefreshReg$;
  prevRefreshSig = window.$RefreshSig$;

  window.$RefreshReg$ = (type, id) => {
    RefreshRuntime.register(type, "C:/blablabla/AttributeEditor/index.js" + " " + id);
  };

  window.$RefreshSig$ = RefreshRuntime.createSignatureFunctionForTransform;
}

var _s = $RefreshSig$();

from what I've seen sourceMaps are not taking into account those lines and it offset the sourceMaps by something like 12 to 15 lines. This is my observation, I might be wrong, but removing the generated code HMR setup fixes the source maps completely.

I'm trying to disable HMR to see source maps, but setting:

server: { hmr: false },

does not do anything. This code is still being generated and source maps are off.

@DanielLaberge
Copy link

This is a major deal breaker issue for our team and is blocking our migration from Webpack.

I don't understand how such a critical bug can go unresolved for so long, did we miss a workaround or something?

Any feedback from the vite.js team would be much appreciated.

@ThePainnn
Copy link

ThePainnn commented Jul 21, 2022

Found my issue! I was using vite-plugin-require because we had a couple of them. I manage to remove all except one so I use the exclude option:

  return defineConfig({
    plugins: [
      react(),
      vitePluginRequire({
        fileRegex:/(config.js)$/
      }),

When analysing source maps with this plugin, they come out quite differently. Some newline are inserted that are messing up source maps.

You can repro with a very simple project
testvite.zip

I hope this solve the issue for a bunch of you!

Cheers!

@MisaelMP
Copy link

I have exactly the same issue, I can't use debugger or breakpoints at all using Vite, any idea how to fix this?

@u12206050
Copy link

Any update on this? I can connect the debugger to the compiled JS files in vscode, but unable to link it all the way to the original TS files.

@jackchoumine
Copy link

I have same issue.

const Button = defineComponent({
  setup(props, { slots }) {
    console.log('*****slots')
    console.log(slots)
    const { default: _default, left, right } = slots
    //NOTE  CAN NOT REACH HERE
    debugger
    return () => (
      <button style={style}>
        {left ? left() : null}
        {_default ? _default() : 'BUTTON'}
        {right ? right() : null}
      </button>
    )
  },
})

@CreativeWarlock
Copy link

Looks like no one cares to fix this.
I recently updated my Vue project to use Vite and many nasty random vite errors pop up during page load that seem to originate out of nowhere (reloading the page several times and it miraculously works).
Debugging is not possible because breakpoints are not binding. Completely out of ideas...

@patak-dev patak-dev transferred this issue from vitejs/vite Dec 3, 2022
@madsnedergaard
Copy link

madsnedergaard commented Dec 21, 2022

This is also a problem in react (see vitejs/vite-plugin-react#23), so maybe it should be on a higher level than this plugin?

@matija2209
Copy link

hmr: false

That worked for me. I'm using Vite 4.x and React with Typescript. Until that change, Vite was unusable for me. I was very close to switching. Thanks

@cryptoGF
Copy link

cryptoGF commented Jan 12, 2023

similar problem here:

  • I couldn't set breakpoint on some certain lines of code.
  • sometimes the breakpoint is drifting to another line.
  • you can set a breakpoint on an empty line.
  • when a breakpoint gets hit, the variable declared above is undefined where it is in fact not. (this is probably because the actual mapped line of code has not been executed)

It seems all the above behaviors are due to the out of sync source maps
Here's a simple example of how the inline source map was wrong on one of my project SFC:
link to incorrect source map example

@yyx990803
is there any post process that vue-loader does to the <script> section after tsc so that the source map doesn't match ??
we count on you to fix this... debugging is anyway essential to devs.

@hspaay
Copy link
Author

hspaay commented Jan 12, 2023

@cryptoGF Yes I think that Vite doesn't do HMR. Source maps are correct until a HMR takes place. As @matija2209 confirmed, disabling mhr does often make debugging workable.

@baiej214
Copy link

baiej214 commented Jan 31, 2023

这问题一年过去了还没解决吗?官方为什么没人说明一下呢?
hmr: false的方式有用,不过修改代码后的第一次手动刷新还是不行,需要多一次刷新才行。。。

@tingshuai
Copy link

我的项目也出现了相同问题;经过多次测试。发现使用了element-plus全局自动按需引入后会出现这个问题;具体是因为unplugin-vue-components、unplugin-auto-import这两个包。当安装了这两个包后发现node_modules里面会多出几个webpack相关的包;
卸载后断点正常;

@Tobiaqs
Copy link

Tobiaqs commented Mar 14, 2023

I can't speak for everyone because my setup is slightly unusual, but I'm able to debug a Vue 3 SFC TS application in VSCode using the Firefox extension. Here is my raw config (note that my frontend project is a subfolder of the workspace folder).

My config is unusual because in development, a Django application serves a HTML which includes scripts from another virtual host, where Vite is running.

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "firefox",
            "request": "launch",
            "name": "vuejs: firefox",
            "url": "https://theproject.dev.somedomain.nl",
            "pathMappings": [
                {
                    "url": "file:///app", // /app is the path where my frontend project is mounted in a docker container running Vite
                    "path": "${workspaceFolder}/frontend"
                },
                {
                    "url": "https://frontend.theproject.dev.somedomain.nl/node_modules",
                    "path": "${workspaceFolder}/frontend/node_modules"
                }
            ],
            "profile": "default",
            "keepProfileChanges": true,
            "log": {
                "consoleLevel": {
                    "PathConversion": "Debug",
                    "default": "Error"
                },
            },
            "skipFiles": [
                "${workspaceFolder}/frontend/node_modules/**/*.js"
            ],
        }
    ]
}

This is what it should look like if I adjust the paths to those of a regular setup

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "firefox",
            "request": "launch",
            "name": "vuejs: firefox",
            "url": "http://localhost:5173",
            "pathMappings": [
                {
                    "url": "file://${workspaceFolder}",
                    // "url": "file:///home/me/repos/myviteproject", // Alternatively...
                    "path": "${workspaceFolder}"
                },
                // Only mapping node_modules so we are able to ignore exceptions originating from there (see skipFiles)
                {
                    "url": "http://localhost:5173/node_modules",
                    "path": "${workspaceFolder}/node_modules"
                }
            ],
            "profile": "default",
            "keepProfileChanges": true, // Don't forget my cookies every time
            "log": {
                "consoleLevel": {
                    "PathConversion": "Debug", // Show debug messages about path mapping
                    "default": "Error"
                },
            },
            "skipFiles": [
                "${workspaceFolder}/node_modules/**/*.js" // Ignore node_modules exceptions
            ],
        }
    ]
}

@Tobiaqs
Copy link

Tobiaqs commented Mar 16, 2023

So the key is to use file://${workspaceFolder} as URL in your mapping. Maybe this also works for Chrome?

@hspaay
Copy link
Author

hspaay commented Mar 30, 2023

@khaledOghli Thanks for the tip but I don't think this solves the issue.
Hmr works fine when enabled. The problem is that it updates the source maps get out of sync with the sources themselves. The result is that breakpoints end up on the wrong line.

@Tobiaqs interesting. I'm no longer using vue because of this issue, but maybe someone else can test this?

@perintery
Copy link

我的项目也出现了相同问题;经过多次测试。发现使用了element-plus全局自动按需引入后会出现这个问题;具体是因为unplugin-vue-components、unplugin-auto-import这两个包。当安装了这两个包后发现node_modules里面会多出几个webpack相关的包; 卸载后断点正常;

正常指, 可以在chrome中断点了?

@perintery
Copy link

perintery commented Apr 13, 2023

我说一下自己的分析: 我使用的vite+react+ts的项目

  1. 项目跑起来来后, 在chrome的source文件里面看到的其实就是编译后的js代码, 我们在里面断点时候, 断点就打在这个文件上面
  2. 当我们更新源文件的时候, 触发hmr流程, 最后会加载一个新的编译好的js文件, 我们打断点的那个文件, 已经不会被执行到了.

所以要接这个问题, 就是怎么把old文件上的断点信息,带到新的文件上面来.


I'll give my own analysis: I'm using a project with vite+react+ts.

After running the project, what we see in the source files in Chrome is actually the compiled JS code. When we set a breakpoint in it, it is set on this file.
When we update the source file, it triggers the HMR process and finally loads a new compiled JS file. The file where we set the breakpoint will not be executed anymore.
So the question is how to transfer the breakpoint information from the old file to the new file?


how?

@yyx990803
Copy link
Member

yyx990803 commented Apr 25, 2023

To clarify, debugging is currently working fine with Chrome Devtools' debugging for the following cases:

  1. debugger statements in source code, e.g. @click="debugger; count++"
  2. Breakpoints attached via Chrome Devtools' Source panel.

It only breaks after HMR if the debugging is done by launching via VSCode. So the solution is to prefer Chrome's native debugger instead of VSCode's debugger. You'll also find that Chrome's native debugger is more reliable and much faster.

As for the VSCode issue, it is not really caused by Vue or plugin-vue, but an incompatibility between VSCode's debugger and how Vite HMR works. I'm not sure if this is something we can fix - if anything, this seems to be something VSCode should be fixing since Vite is working fine with Chrome's native debugger as far as I can tell.

@hspaay
Copy link
Author

hspaay commented Apr 26, 2023

Hmm, not saying you're wrong, but this is a bit of a stretch. Saying that 'since it works in chrome it can't be vite' has a few shortcomings.

  1. This is just an assumption. Without understanding the root cause this statement is unfounded.
  2. The problem exists for both VSCode and Jetbrains Intellij. Are both tools to blame for not handling typescript/HMR properly?

I think it is incorrect to close this issue as nothing has been resolved.

@rotu
Copy link

rotu commented May 7, 2023

I encountered this too, and I think the issue is "content validation" in the vscode-js-debug extension. I think I found that adding "enableContentValidation": false in my launch configuration fixes this issue.

launch.json:

{
   "version": "0.2.0",
   "configurations": [
      {
         "type": "chrome",
         "request": "launch",
         "name": "Chrome",
         "url": "http://localhost:8080",
         "enableContentValidation": false
      }
   ]
}

Here's what the documentation for enableContentValidation says:

Toggles whether we verify the contents of files on disk match the ones loaded in the runtime. This is useful in a variety of scenarios and required in some, but can cause issues if you have server-side transformation of scripts, for example.

https://github.com/microsoft/vscode-js-debug/blob/8afb1e8c421a3bef2b0e264bc9e00f7b4922b02c/src/adapter/threads.ts#L1479

@hspaay, can you check if this fixes debugging for you too?

@github-actions github-actions bot locked and limited conversation to collaborators May 22, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests