microsoft / vscode-js-debug

A DAP-compatible JavaScript debugger. Used in VS Code, VS, + more
MIT License
1.64k stars 271 forks source link

Cannot get URLs to map via sourceURL= to local files (same files map in Chrome DevTools) #898

Closed davidpcaldwell closed 3 years ago

davidpcaldwell commented 3 years ago

I initially filed this under "Other" because I didn't have a great test case, but I have subsequently created one -- see below.

I can't get URLs executed via eval()ed source code that uses //# sourceURL=[url] to specify the source location to map to local files when developing.

I've created a GitHub gist to illustrate.

Steps to reproduce:

  1. Clone the gist into a directory.
  2. Start a server that serves that directory.
  3. Copy launch.json to .vscode/launch.json (sorry, gists cannot contain directories)
  4. Open VSCode to that directory
  5. Start a Chrome instance with the debugger on port 9222

Test case 1: Open browser to [server]/index.html

This will cause the sourceURL "eval.js" to be used for the evaluated eval.js script. Note that the script.js script maps correctly, but that VSCode will not map the eval.js script to the local eval.js (Chrome DevTools will, if you mount the directory in the Filesystems tab.)

Test case 2: Open browser to [server]/index.html?full

This will cause the sourceURL "[server]/eval.js" to be used for the evaluated eval.js script. Note that VSCode will not map the script to the local eval.js (Chrome DevTools will, if you mount the directory in the Filesystems tab.)

Should this work? Or am I on the wrong path?

connor4312 commented 3 years ago

Thanks for the issue. This doesn't work because the debugger recognizes that the script which is running is different (has different contents) from the version that's on disk, so it doesn't map it to the path. This behavior is especially important in scenarios where there's in-place transpilation of code to avoid mapping the compiled code to the uncompiled code.

If you want to disable this functionality, you can do so by setting enableContentVerification: false in your launch.json:

{
  "configurations": [
    {
      "name": "Launch Chrome",
      "request": "launch",
      "type": "pwa-chrome",
      "url": "http://localhost:5000",
      "webRoot": "${workspaceFolder}",
      "enableContentValidation": false
    }
  ]
}
davidpcaldwell commented 3 years ago

So is what you're saying that the addition of //# sourceURL=... itself is the modification, and is what is causing the mismatch?

connor4312 commented 3 years ago

That's right. Chrome sends us the hash of each script it loads and we do the same hash in the debugger. If they mismatch, the sources are different.

davidpcaldwell commented 3 years ago

Thanks. I think I'll use the flag you indicated.

Longer-term, do you know anything about how Chrome does this? It somehow is recognizing them as the same even with the transformation. (Or maybe it does no validation at all?)

Or, put the other way, it seems like eval() scripts without source maps will never work without disabling content validation. Does that sound right to you? I'm not an expert on how all this works.

connor4312 commented 3 years ago

Chrome doesn't do validation. It doesn't need to deal with transpilation and map to the filesystem to the extent that VS Code does.

eval scripts can work without the flag if the contents being evaluated are identical to what's on disk.

davidpcaldwell commented 3 years ago

Right, so by "identical to what's on disk" you mean that the //# sourceURL= would need to be part of the source code, right?

By the way, disabling content validation did work correctly, for the most part. I'm having trouble with getting breakpoints hit but I recall some workarounds for that (at least with the old debugger) and so I'll dig into it a bit.

Thank you!

davidpcaldwell commented 3 years ago

When I refresh the page my breakpoints become "unbound" and don't get hit.

Using the debugger keyword is a successful workaround -- if I can interrupt the script that way, I can then set subsequent breakpoints that will get hit. I'll keep digging into whether there's a more robust way to do that.

In any case, I'm much better off than when we started, so thank you!

davidpcaldwell commented 3 years ago

I may be seeing bug #884 -- I am running code on page reload and expect the breakpoints to be hit then; if #884 is correct, they will never be hit (because they're not triggered by a button or anything; this is a testing framework, so it just runs the tests when the browser loads).

davidpcaldwell commented 3 years ago

However, if I open those in a JavaScript Debug Terminal, they do get hit. If I can make sense of this all, I'll file a new issue.

connor4312 commented 3 years ago

I just fixed #884. Part of it shared a root cause with #883 but I also fixed a race condition which could, on reload, cause breakpoints to appear unbound. There's a nightly build where these'll be available. Give me a shout if you continue to run into problems.

davidpcaldwell commented 3 years ago

Thanks. I don't have the behavior nailed down completely yet, I don't think. The debugger workaround may end up being sufficient for my needs. Do extensions get updated with the main VSCode builds, or do they autoupdate somehow? Just trying to figure out if I don't switch to the nightlies when to re-test with your fix.

davidpcaldwell commented 3 years ago

Just to be super-clear, though, in my case they'd be unbound at the beginning, then I could hit a debugger statement and bind them, and they'd remain bound until I refreshed (i.e., reloaded the page, or restarted from the debugger), when I could (in real time) watch them become unbound again. Don't know if that's helpful.

connor4312 commented 3 years ago

Yep, that sounds like it.

The extension will be updated with the next VS Code stable build at the end of this month.

davidpcaldwell commented 2 years ago

Fascinating, I was trying to debug in VSCode, couldn't get my breakpoints to be hit, searched the issue database, saw this issue that looked like it might be relevant, opened it, and:

  1. Found that I was the reporter of the original issue,
  2. Found that I'd been given some advice about how to resolve the issue,
  3. Found that that advice worked.

Glad the internet has a better memory than I do!