microsoft / react-native-windows

A framework for building native Windows apps with React.
https://microsoft.github.io/react-native-windows/
Other
16.21k stars 1.13k forks source link

Trying to debug RNW app (Hermes Direct Debug) with Visual Studio gives "TargetDescriptor cannot be null" error #12113

Closed jonthysell closed 5 months ago

jonthysell commented 11 months ago

Problem Description

Visual Studio supposedly contains the same debugging support for Node.js / Chrome Dev Protocol as Visual Studio Code. To test this I've tried attaching the Visual Studio debugger to an RNW app running with Hermes and Direct Debugging with the following settings (the only settings that lets me attach to anything AFAIK):

image

But I get the following error message:

image

Steps To Reproduce

Create and build new app with Hermes and Direct Debugging enabled

  1. npx react-native@latest init testdebug72
  2. cd testdebug72
  3. npx react-native-windows-init --overwrite
  4. Change UseHermes to true in windows\ExperimentalFeatures.props
  5. Change UseWebDebugger to false and UseDirectDebugger to true in windows\testdebug72\App.cpp
  6. npx react-native run-windows --logging

Try to attach Visual Studio debugger

  1. Open Visual Studio 2022 with no code (Node.js development support installed)
  2. Open Debug > Attach to Process a. Connection type: JavaScript and TypeScript (Chrome DevTools/V8 Inspector) b. Connection target: ws://127.0.0.1:8081 c. Attach to: JavaScript and TypeScript
  3. Click Attach

Expected Results

Debugger attaches, loads the source map from Metro, and lets me debug the JS code.

CLI version

11.3.6

Environment

info Fetching system and libraries information...
System:
  OS: Windows 10 10.0.25941
  CPU: (8) x64 Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz
  Memory: 2.81 GB / 15.84 GB
Binaries:
  Node:
    version: 18.17.0
    path: C:\Program Files\nodejs\node.EXE
  Yarn:
    version: 1.22.19
    path: C:\Program Files (x86)\Yarn\bin\yarn.CMD
  npm:
    version: 9.6.7
    path: C:\Program Files\nodejs\npm.CMD
  Watchman: Not Found
SDKs:
  Android SDK: Not Found
  Windows SDK:
    AllowDevelopmentWithoutDevLicense: Enabled
    AllowAllTrustedApps: Enabled
    Versions:
      - 10.0.16299.0
      - 10.0.18362.0
      - 10.0.19041.0
      - 10.0.22000.0
      - 10.0.22621.0
IDEs:
  Android Studio: Not Found
  Visual Studio:
    - 16.11.33927.289 (Visual Studio Enterprise 2019)
    - 17.7.34009.444 (Visual Studio Enterprise 2022)
Languages:
  Java: Not Found
  Ruby: Not Found
npmPackages:
  "@react-native-community/cli": Not Found
  react:
    installed: 18.2.0
    wanted: 18.2.0
  react-native:
    installed: 0.72.4
    wanted: 0.72.4
  react-native-windows:
    installed: 0.72.8
    wanted: 0.72.8
npmGlobalPackages:
  "*react-native*": Not Found
Android:
  hermesEnabled: true
  newArchEnabled: false
iOS:
  hermesEnabled: Not found
  newArchEnabled: Not found

Target Platform Version

10.0.19041

Target Device(s)

Desktop

Visual Studio Version

Visual Studio 2022

Build Configuration

Debug

Snack, code example, screenshot, or link to a repository

No response

acoates-ms commented 11 months ago

Can you try with localhost:9222, 9223, and 9229. I think the instance will be exposing the debugging protocol on one of those ports?

Not sure what the webkit thing you tried to attach to was, but I dont think that was RN.

jonthysell commented 11 months ago

Can you try with localhost:9222, 9223, and 9229. I think the instance will be exposing the debugging protocol on one of those ports?

Not sure what the webkit thing you tried to attach to was, but I dont think that was RN.

That's what I'm trying to find out. I filed this bug as a reference point to talk with the VS folks. Everywhere else (Chrome/Edge DevTools, VS Code) you must connect to localhost:8081 to connect to Metro's proxy to Hermes. Despite the documentation and capacity to change it, the 922X ports don't work in any Hermes debugging scenario I've tried. Here's what I get with any combination of http/ws, 127.0.0.1/localhost, and 9222/9223/9229 with VS:

image

EricCornelson commented 11 months ago

I think I see what the issue is. We do want to connect to localhost:8081, since the bundler is publishing the list of debug targets (which you can see from localhost:8081/json). There's some code in the attach flow (in Visual Studio) that assumes that the Id field for a debug target will be a Guid, and we try to parse the guid to use as the guid for the debug struct we pass to the debug engine to create a possible attachment.

[
  {
    "id": "0-3", // <---- we expect this to be a guid, and since it's not, we aren't seeing this as a valid target to add in the list
    "title": "Hermes",
    "faviconUrl": "https://reactjs.org/favicon.ico",
    "devtoolsFrontendUrl": "devtools://devtools/bundled/js_app.html?experiments=true&v8only=true&ws=%5B%3A%3A1%5D%3A8081%2Finspector%2Fdebug%3Fdevice%3D0%26page%3D3",
    "type": "node",
    "webSocketDebuggerUrl": "ws://[::1]:8081/inspector/debug?device=0&page=3",
    "vm": "Hermes",
    "deviceName": "DESKTOP-VDBOC6B"
  }
]

I'll see if we can just spoof the guid, or if there's any real need for that to be consistent across attach attempts.

acoates-ms commented 11 months ago

Is it defined in the CDB protocol that this is supposed to be a guid? Or is it allowed to be any string? (Is this a bug in our implementation, or a bad assumption in VS)?

EricCornelson commented 11 months ago

I think it's a bad assumption in VS. The CDP spec defines the target id as just a string, but it just happens to be a guid everywhere in V8.

https://chromedevtools.github.io/devtools-protocol/tot/Target/#type-TargetID

jonthysell commented 11 months ago

Ok, so as an experiment I modified the metro-inspector-proxy to return a guid, ie http://localhost:8081/json returns:

[
    {
        "id": "{00000000-0000-0000-0000-00000000000000000000001}",
        "title": "Hermes",
        "faviconUrl": "https://reactjs.org/favicon.ico",
        "devtoolsFrontendUrl": "devtools://devtools/bundled/js_app.html?experiments=true&v8only=true&ws=%5B%3A%3A1%5D%3A8081%2Finspector%2Fdebug%3Fdevice%3D0%26page%3D1",
        "type": "node",
        "webSocketDebuggerUrl": "ws://[::1]:8081/inspector/debug?device=0&page=1",
        "vm": "Hermes",
        "deviceName": "JAUNTYPAD"
    }
]

However, if I try to set VS to attach to http://localhost:8081 it doesn't ever even hit the codepath in metro which enumerates that list (i.e. /json). However, I can set VS to attach directly to ws://[::1]:8081/inspector/debug?device=0&page=1 and am able to debug Hermes successfully (with source maps and everything)!

image

So what's the missing link here?

EricCornelson commented 10 months ago

This should be fixed in the latest preview of VS. Give it another shot and let me know if it works as expected.

jonthysell commented 5 months ago

@EricCornelson Connecting in VS 17.9.3 I do see "Hermes" in the connection now:

image

However I still get an error when trying to connect:

image

JSON from http://localhost:8081/json:

    {
        "id": "0-1",
        "title": "Hermes",
        "faviconUrl": "https://reactjs.org/favicon.ico",
        "devtoolsFrontendUrl": "devtools://devtools/bundled/js_app.html?experiments=true&v8only=true&ws=localhost%3A8081%2Finspector%2Fdebug%3Fdevice%3D0%26page%3D1",
        "type": "node",
        "webSocketDebuggerUrl": "ws://localhost:8081/inspector/debug?device=0&page=1",
        "vm": "Hermes",
        "deviceName": "JauntyPad"
    }
]

Is your fix in 17.9.3? Or is this something else? My previous workaround (connecting direct to ws://localhost:8081/inspector/debug?device=0&page=1 no longer appears to be working).

jonthysell commented 5 months ago

Added logging after calling DebugAdapterHost.Logging /On /OutputWindow in the Command Window:

 1> DebugAdapterHost version: 17.6.10907.1 commit:6fef36f95dd1139788bfdde4ba25a71b4ccdc1aa
 1> [JavaScriptDebuggerExtensions] About to compile the list of startup projects for the source mapper's internal cache.
 1> [JavaScriptDebuggerExtensions] Succesfully compiled the startup projects' list for the source mapper's internal cache: C:\code\test73\windows\test73\test73.vcxproj
 1> [JavaScriptDebuggerExtensions] About to compile the list of all loaded projects for the source mapper's internal cache.
 1> ERROR: [JavaScriptDebuggerExtensions] Get file path of project for logging purposes failed due to: System.NotImplementedException: Not implemented (Exception from HRESULT: 0x80004001 (E_NOTIMPL))
   at System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)
   at Microsoft.VisualStudio.WebClient.Diagnostics.URLToFilePathMapper.GetMkDocumentForProject(IVsProject project, UInt32 itemId)
   at Microsoft.VisualStudio.WebClient.Diagnostics.URLToFilePathMapper.PopulateMultipleProjectToFilePathsMapping(IEnumerable`1 projects):
   at System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)
   at Microsoft.VisualStudio.WebClient.Diagnostics.URLToFilePathMapper.GetMkDocumentForProject(IVsProject project, UInt32 itemId)
   at Microsoft.VisualStudio.WebClient.Diagnostics.URLToFilePathMapper.PopulateMultipleProjectToFilePathsMapping(IEnumerable`1 projects)
 1> ERROR: [JavaScriptDebuggerExtensions] Get file path of project for logging purposes failed due to: System.NotImplementedException: The method or operation is not implemented.
   at System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)
   at Microsoft.VisualStudio.WebClient.Diagnostics.URLToFilePathMapper.GetMkDocumentForProject(IVsProject project, UInt32 itemId)
   at Microsoft.VisualStudio.WebClient.Diagnostics.URLToFilePathMapper.PopulateMultipleProjectToFilePathsMapping(IEnumerable`1 projects):
   at System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)
   at Microsoft.VisualStudio.WebClient.Diagnostics.URLToFilePathMapper.GetMkDocumentForProject(IVsProject project, UInt32 itemId)
   at Microsoft.VisualStudio.WebClient.Diagnostics.URLToFilePathMapper.PopulateMultipleProjectToFilePathsMapping(IEnumerable`1 projects)
 1> [JavaScriptDebuggerExtensions] Succesfully compiled the list of all loaded projects for the source mapper's internal cache: C:\code\test73\windows\test73\test73.vcxproj, C:\code\test73\node_modules\react-native-windows\Folly\Folly.vcxproj, C:\code\test73\node_modules\react-native-windows\fmt\fmt.vcxproj, C:\code\test73\node_modules\react-native-windows\ReactCommon\ReactCommon.vcxproj, C:\code\test73\node_modules\react-native-windows\Chakra\Chakra.vcxitems, C:\code\test73\node_modules\react-native-windows\Microsoft.ReactNative\Microsoft.ReactNative.vcxproj, C:\code\test73\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems, C:\code\test73\node_modules\react-native-windows\Common\Common.vcxproj, System.__ComObject@56760589, C:\code\test73\node_modules\react-native-windows\Shared\Shared.vcxitems, C:\code\test73\node_modules\react-native-windows\Mso\Mso.vcxitems, C:\code\test73\node_modules\react-native-windows\include\Include.vcxitems, [Shared MSBuild Project Files], Microsoft.VisualStudio.CommonIDE.Solutions.ProjectSystems.MiscellaneousFilesProject@44895264
 1> ERROR: Failed to parse launch configuration JSON.

NullReferenceException: Object reference not set to an instance of an object.

Microsoft.VisualStudio.WebClient.Diagnostics.HtmlToolHost.Utilities.DteWorkspacePathProvider.MatchesNodeUrl(Project project, String url)
System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source, Func`2 predicate)
Microsoft.VisualStudio.WebClient.Diagnostics.HtmlToolHost.Utilities.DteWorkspacePathProvider.WorkspaceRoot(CdpDebugTargetDescriptor descriptor, Boolean appendWwwRoot)
Microsoft.VisualStudio.WebClient.Diagnostics.HtmlToolHost.PineZorro.LaunchConfiguration.ExtractAttachConfiguration(IAdapterLaunchInfo launchInfo, IWorkspacePathProvider workspacePathProvider, ILogger logger)
Microsoft.VisualStudio.WebClient.Diagnostics.HtmlToolHost.PineZorro.LaunchConfiguration.FromLaunchInfo(IAdapterLaunchInfo launchInfo, IWorkspacePathProvider workspacePathProvider, ILogger logger)
Microsoft.VisualStudio.WebClient.Diagnostics.AdapterLauncher.<>c__DisplayClass37_0.<UpdateLaunchOptions>b__0(ITelemetryReporter reporter)
Microsoft.VisualStudio.WebClient.Diagnostics.HtmlToolHost.Telemetry.TelemetryReporterFactory.ReportOperation(TelemetryNamespace telemetryNamespace, String entityName, String eventDescription, Action`1 operationToReport, Boolean isUserTask)
Microsoft.VisualStudio.WebClient.Diagnostics.HtmlToolHost.Telemetry.TelemetryReporterFactory.ReportUserTask(String entityName, String eventDescription, Action`1 operationToReport)
Microsoft.VisualStudio.Debugger.VSCodeDebuggerHost.AdapterHosting.DebugAdapterHostFactory.CreateDebugAdapterHost(ConfigurationWrapper configuration, IDiagnosticLogger log, ExtensibilityManager extensibilityManager, IAdapterLaunchInfo launchInfo, ITargetHostInterop targetInterop, Boolean registerStandardHandlers, DebugProtocolOptions options, Action`1 syncRequestErrorHandler)

 1> ERROR: Unexpected error

DebugAdapterLaunchException: Failed to launch debug adapter.  Additional information may be available in the output window.

Microsoft.VisualStudio.Debugger.VSCodeDebuggerHost.AdapterHosting.DebugAdapterHostFactory.CreateDebugAdapterHost(ConfigurationWrapper configuration, IDiagnosticLogger log, ExtensibilityManager extensibilityManager, IAdapterLaunchInfo launchInfo, ITargetHostInterop targetInterop, Boolean registerStandardHandlers, DebugProtocolOptions options, Action`1 syncRequestErrorHandler)
Microsoft.VisualStudio.Debugger.VSCodeDebuggerHost.AdapterHosting.DebugAdapterHostFactory.CreateDebugAdapterHost(DebuggedProcess process, IAdapterLaunchInfo launchInfo, ITargetHostInterop targetInterop)
Microsoft.VisualStudio.Debugger.VSCodeDebuggerHost.Engine.Implementation.DebuggedProcess.StartDebugAdapter(IAdapterLaunchInfo launchInfo, ITargetHostInterop targetInterop)

Failure Location: ReadingConfiguration
Inner Exception: 
    NullReferenceException: Object reference not set to an instance of an object.

Microsoft.VisualStudio.WebClient.Diagnostics.HtmlToolHost.Utilities.DteWorkspacePathProvider.MatchesNodeUrl(Project project, String url)
System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source, Func`2 predicate)
Microsoft.VisualStudio.WebClient.Diagnostics.HtmlToolHost.Utilities.DteWorkspacePathProvider.WorkspaceRoot(CdpDebugTargetDescriptor descriptor, Boolean appendWwwRoot)
Microsoft.VisualStudio.WebClient.Diagnostics.HtmlToolHost.PineZorro.LaunchConfiguration.ExtractAttachConfiguration(IAdapterLaunchInfo launchInfo, IWorkspacePathProvider workspacePathProvider, ILogger logger)
Microsoft.VisualStudio.WebClient.Diagnostics.HtmlToolHost.PineZorro.LaunchConfiguration.FromLaunchInfo(IAdapterLaunchInfo launchInfo, IWorkspacePathProvider workspacePathProvider, ILogger logger)
Microsoft.VisualStudio.WebClient.Diagnostics.AdapterLauncher.<>c__DisplayClass37_0.<UpdateLaunchOptions>b__0(ITelemetryReporter reporter)
Microsoft.VisualStudio.WebClient.Diagnostics.HtmlToolHost.Telemetry.TelemetryReporterFactory.ReportOperation(TelemetryNamespace telemetryNamespace, String entityName, String eventDescription, Action`1 operationToReport, Boolean isUserTask)
Microsoft.VisualStudio.WebClient.Diagnostics.HtmlToolHost.Telemetry.TelemetryReporterFactory.ReportUserTask(String entityName, String eventDescription, Action`1 operationToReport)
Microsoft.VisualStudio.Debugger.VSCodeDebuggerHost.AdapterHosting.DebugAdapterHostFactory.CreateDebugAdapterHost(ConfigurationWrapper configuration, IDiagnosticLogger log, ExtensibilityManager extensibilityManager, IAdapterLaunchInfo launchInfo, ITargetHostInterop targetInterop, Boolean registerStandardHandlers, DebugProtocolOptions options, Action`1 syncRequestErrorHandler)

 1> ERROR: Failed to launch debug adapter.  Additional information may be available in the output window.

Object reference not set to an instance of an object.
jonthysell commented 5 months ago

Okay, I've got debugging to work as long as you have VS 17.9.3 or greater. The only remaining issue is having the UWP project opened in VS when trying to attach. If you just start VS with no code, you can attach just fine. New issue tracking that here: #12842