Unreal.js icon indicating copy to clipboard operation
Unreal.js copied to clipboard

VSCode not stopping on breakpoints

Open imre-chroncsik opened this issue 7 years ago • 1 comments

I'm having problems with breakpoints, both in Visual Studio Code and in Chrome devtools. Apparently when a file is require()'ed, a new temporary file gets created, which wraps the contents of the original file into a function. I believe this is standard behavior in node.js, not sure who does this in Unrealjs. In any case, looks like this confuses the debugger; as the preprocessed / wrapped file is being executed, the debugger won't pick up any breakpoints that are set in the original file. Maybe some source mapping would be required?

(The issue is similar to https://github.com/ncsoft/Unreal.js/issues/66, except that the solution mentioned there doesn't seem to work for me.)

This is what I experience:

  • Download the demo project.
  • Open the demo/Content/Scripts folder in Visual Studio Code.
  • Open and start the game in Unreal Editor. According to what happens on screen, and the logs in the Javascript console, JS code is running fine.
  • In the JS console, execute Context.CreateInspector(9229), then Context.SetAsDebugContext().
  • Attach with Visual Studio Code (using the inspector protocol, on port 9229).
  • Console output is now showing up in VS Code, so looks like attaching actually worked.
  • Add a breakpoint in demo/demo-cable.js, on the first line of the demo() function.
  • In the game, hit the Cables button.
  • VSCode should now stop execution at the breakpoint, but doesn't.
  • Now add a debugger statement at the top of the demo() function in demo-cable.js, hit the Cables button in the game again.
  • Debugger now properly stops at the debugger statement.
  • BUT, not in the original demo-cable.js file. Instead, VSCode opens a new tab, with a modified (node-module-wrapped) copy of demo-cable.js, stating that it's a "read-only core module", in "node_internals". Link to screenshot: https://photos.google.com/share/AF1QipPHQffnyWqd_7SRzsDKATdFwaJ31GfA-s4KuGT-ME-WbLoC48IxI4yciefUOZYtVw?key=U3BZZWhDWm00ZmstWFhTNHNQTFM5LTFReV9zUVJR
  • In this modified demo-cable.js file, now I can add breakpoints that do actually work. (But this isn't really good developer experience, especially as this file is now read-only.)

Is this behavior expected? Is there any way to make breakpoints that are set in the original source file work? Thanks.

imre-chroncsik avatar Jun 04 '18 07:06 imre-chroncsik

I only had the time now to get back to this. Looks like it's an issue about path / url formats.

When adding a script to v8, UJS converts the path into a URL by prefixing with "file:///". (LocalPathToURL() also includes code to replace backslashes to forward slashes, but in my debugging session the incoming path always already had forward slashes.) VSCode uses setBreakpointByUrl to add a new breakpoint, and passes a urlRegex to it, that looks like "[Ee]:\\unreal_project\\Content\\Scripts\\game\.js". Note how there's no "file:///" prefix, and it uses backslashes. v8 doesn't find the script this way, and its reply to the setBreakpointByUrl call will contain an empty 'locations' array, hence VSCode reports that the breakpoint could not be resolved.

My first attempt for a workaround was patching the urlRegex coming in from VSCode (add the prefix, convert to forward slashes). That almost works, v8 does find the file, reports the correct location, and also stops at the breakpoint, but this results in another problem: when stopping at a breakpoint, now v8 gives VSCode a script location (URL) that VSCode won't recognize. In this case VSCode reads the full script source from v8, and displays it on a new tab (stating that it's a "node internal" source), unable to map it to the original script file. (This also breaks any source maps, eg. if using TypeScript.)

The workaround that now seems to work for me is this:

  • In JavaScriptContext_Private.cpp, RunScript(), when building the ScriptOrigin, I do not call LocalPathToURL(). In practice this means that the path won't have the "file:///" prefix (but will have forward slashes).
  • In Inspector.cpp, dispatchFrontendMessage(), when getting a setBreakpointByUrl call, I patch the incoming urlRegex by replacing backslashes to forward slashes.
  • This way the path with which the script is registered at v8 is consistent with the path that we later use to find the script when adding a breakpoint, so v8 can now properly find the script and resolve the breakpoint location.
  • When stopping at a breakpoint, v8 passes to VSCode a path with forward slashes, but apparently VSCode is able to cope with that, and properly stops at the breakpoint.
  • This also fixes the source map issues I previously had: now VSCode doesn't open a new tab, and can even stop in a .ts file if a source map is available. I can also add new breakpoints directly in the .ts.

I still don't think that this is a good solution, as the way I'm messing with the paths might easily be incompatible with other platforms or debuggers.

So I think there are two possible ways to go forward: a) Does anyone more familiar with VSCode know if it's possible to set up VSCode to use a path format that is consistent with that used in UJS? That is, use proper "file:///"-prefixed URLs? b) If a) isn't possible, then maybe we could have some kind of a ScriptPathFormat in UJS, with a possible value that would make UJS use the VSCode format (no "file:///" prefix)?

imre-chroncsik avatar Jul 10 '18 06:07 imre-chroncsik