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 node process started by Bazel from VSCode #823

Closed
alexeagle opened this issue Jun 5, 2019 · 6 comments · Fixed by #1618
Closed

Debugging node process started by Bazel from VSCode #823

alexeagle opened this issue Jun 5, 2019 · 6 comments · Fixed by #1618

Comments

@alexeagle
Copy link
Collaborator

I don't know if this is a real issue, just copying it from the JIRA board.
Not sure how to reproduce. Maybe @vikerman or @Toxicable knows.

@Toxicable
Copy link

Toxicable commented Jun 8, 2019

The cause of this issue is this here: bazelbuild/rules_typescript#254
When you have preserve_symlinks = False set

Otherwise if you have preserve_symlinks = True ( the default setting) then you get this one here: https://github.com/bazelbuild/rules_typescript/issues/321

ts_library

preserve_symlinks =True bazelbuild/rules_typescript#254
When debugging a nodejs program in VS Code and you hit a a breakpoint by using the debugger keyword, VS Code will open a the symlinked version of your source file which sits in bazels output dir.
When this happens VS Code will trying to parse all of the TS in this folder causing all TS language support to stop working.
You also cannot use the breakpoint UI in VS Code to set breakpoints, you must use the debugger keyword.

preserve_symlinks = False https://github.com/bazelbuild/rules_typescript/issues/321
When this is set you must once again use the debugger keyword to hit a breakpoint, but when you do the file that VS Code opens is readonly and cannot be edited.

jasmine_node_test

Also another issue that I havn't documented is when you try debugging a source file from under jasmine_node_test VS Code takes you to the JS version of the file, but instead of the line of code being executed the source map points to something like line 3, character 13000, it's only pointing to the AMD header and due to this is effectively useless.

Proposed Solution

The solution I propose to solve this is that we modify the source maps from ts_library to point to the real source files in the users directory.
This could be done by adding a post-processing step to tsc_wrapped which goes through each of the produced sourcemap file and processes it's urls to point back to the original repository.
Which could be implemented as a plugin/transformer

@Toxicable
Copy link

Toxicable commented Jun 8, 2019

One downside I see to this approach is that solving this problem with the ts plugin/transformer approach means it only solves it for files compiled under ts_library.
Which will cover 99% of use cases i'd expect, but im not certain if thats enough.

i've also started on trying this approach here: https://github.com/bazelbuild/rules_nodejs/pull/722/files

@Toxicable
Copy link

Ok after some more investigation the above solution is not a great solution.
We need to find a value for config["compilerOptions"]["sourceRoot"] can allow the source map program to traverse from the runfiles back to the source files.

Here's some better context around the issues here: https://groups.google.com/forum/#!searchin/bazel-discuss/sourcemap$20paths%7Csort:date/bazel-discuss/nv6B0JI9FpI/F91QTAoRAQAJ

@Toxicable
Copy link

Toxicable commented Jun 12, 2019

So we came up with a pretty hacky way to work around this problem in our repository for now.
I wouldn't recommend anyone using this but i'd still like to document it.

The main changes here is that we are passing in a environment variable to tsc_wrapped which allows us to set the sourceRoot for the source maps to an absolute path.
This makes source maps in VSCode work perfectly, for source files, they're still not great for node_modules but one step better then before

below are the specific changes needed to do this
postinstall.js

function replaceInFile(path, before, after) {
  const file = fs.readFileSync(path).toString();
  fs.writeFileSync(path, file.replace(before, after));
}
replaceInFile(
  'node_modules/@bazel/typescript/internal/tsc_wrapped/tsconfig.js',
  `const { options, errors, fileNames } = ts.parseJsonConfigFileContent(config, host, path.dirname(tsconfigFile));`,
  `const { options, errors, fileNames } = ts.parseJsonConfigFileContent(config, host, path.dirname(tsconfigFile)); options["sourceRoot"] = process.env['HACK_WORKSPACE_ABS_DIR'];`
);

BUILD.bazel

nodejs_binary(
    name = "tsc_wrapped__bin",
    entry_point = "@npm//node_modules/@bazel/typescript:internal/tsc_wrapped/tsc_wrapped.js",
    configuration_env_vars = ["HACK_WORKSPACE_ABS_DIR"],
    install_source_map_support = False,
    data = ["@npm//node_modules/@bazel/typescript:typescript__pkg"],
)

defaults.bzl

def ts_library(tsconfig = None, testonly = False, deps = [], module_name = None, **kwargs):
    _ts_library(
        tsconfig = tsconfig,
        testonly = testonly,
        deps = deps,
        module_name = module_name,
        compiler = "//:tsc_wrapped__bin",
        **kwargs
    )

scripts/debug

if [ ! -f .bazelrc.user ]; then
    echo "build --define=HACK_WORKSPACE_ABS_DIR=$(pwd)" > .bazelrc.user
fi
npx ibazel run $1 -- --node_options=--inspect=${2:-9229} --node_options=--trace-warnings

.gitignore

.bazelrc.user

.bazelrc

try-import %workspace%/.bazelrc.user

@Toxicable
Copy link

Toxicable commented Dec 30, 2019

@alexeagle
One way to solve this would be to somehow set the sourceRoot at runtime rather than build time as im doing above.
However, since files are read-only we cant mutate existing files, so any ideas how on some other way we could set the sourceRoot at runtime?
Maybe we could ask source-map if they could add a env var like SOURCE_MAP_ROOT which would override or default the values found in the source maps?

@Toxicable
Copy link

We have a method to solve this now, see the discussion here: microsoft/vscode-chrome-debug-core#549
However we should properly document this before considering this closed.

tsc_wrapped produces source maps that look like sources: ["../../../../../../../../apps/some/path/to/a/file.ts"].
So you can use the sourceMapPathOverrides (https://github.com/microsoft/vscode-chrome-debug/blob/master/README.md#sourcemaps) as part of vscode to rewrite those into proper paths since it has the full workspace relative path.
The idea is just to have an entry to rewrite each level so that any source maps will point to your real source workspaceRoot.
Put this in your .vscode/launch.json and start it with your process running - you may need more levels, depending on your code base

{
      "type": "node",
      "request": "launch",
      "name": "Launch Program",
      "autoAttachChildProcesses": true,
      "internalConsoleOptions": "neverOpen",
      "console": "internalConsole",
      "sourceMapPathOverrides": {
        "../*": "${workspaceRoot}/*",
        "../../*": "${workspaceRoot}/*",
        "../../../*": "${workspaceRoot}/*",
        "../../../../*": "${workspaceRoot}/*",
        "../../../../../*": "${workspaceRoot}/*",
        "../../../../../../*": "${workspaceRoot}/*",
        "../../../../../../../*": "${workspaceRoot}/*",
        "../../../../../../../../*": "${workspaceRoot}/*",
        "../../../../../../../../../*": "${workspaceRoot}/*",
        "../../../../../../../../../../*": "${workspaceRoot}/*",
        "../../../../../../../../../../../*": "${workspaceRoot}/*",
        "../../../../../../../../../../../../../*": "${workspaceRoot}/*",
      }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants