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

Display Bundle Errors in debug console #964

Open
wants to merge 13 commits into
base: main
Choose a base branch
from

Conversation

filip131311
Copy link
Collaborator

@filip131311 filip131311 commented Feb 12, 2025

This PR displays bundle errors in debug console and focuses on the error source, because some bundle errors happen before the application is activated and therefore the cdp debugger we rework how the debug session is created, we first create just a shell of debugSession, that is not connected to the debugger, but is able to log messages into debug console and latter when the application is ready we connect the debugSession to it.

Because this new pattern introduces a possibility of DAP methods being called before debugAdapter is connected to cdp we move cdp related functionality to debug session and return empty responses in case it does not exist yet.

How Has This Been Tested:

-run react-native-78 test app and force bundle error also check if the app is working as expected when syntax is correct.

Screen.Recording.2025-02-19.at.13.55.51.mov

Copy link

vercel bot commented Feb 12, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
radon-ide ✅ Ready (Inspect) Visit Preview 💬 Add feedback Feb 27, 2025 11:41am

Copy link
Member

@kmagiera kmagiera left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some comment inline but also wonder if we could:

We should avoid code where we treat cdpSession as optional, with updates to cdpSession? or cdpSession! – they are perhaps mostly good for now, but when this is a common pattern across this file it may lead to situations where we silently ignore certain error states. I think the best solution would be to try and extract as much code to CDPSession or have some in-between class that could rely on the session being always present. The current change introduces a critical yet implicit state where this class can function with and without sessions and have different behavior.

I wonder how debug session initialization is handled after this change. It appears like this PR is not changing that, therefore the debug adapter will get initialized only after the JS debugger is connected. As a consequence I wonder if and how it will work in the following scenarios:

  1. Can we trigger pause events / errors before debug adapter sends InitializedEvent
  2. Can we land in a state when debug adapter is re-used and re-connected after restart. For example when JS debugger is connected, app crashes in runtime disconnecting the debugger and we hit reload?

@filip131311
Copy link
Collaborator Author

@kmagiera

  1. Can we trigger pause events / errors before debug adapter sends InitializedEvent?

I reworked the approach to focusing and use window.showTextDocument to avoid faking pause events as this solution was not stable enough.

  1. Can we land in a state when debug adapter is re-used and re-connected after restart. For example when JS debugger is connected, app crashes in runtime disconnecting the debugger and we hit reload?

No this is prevented by:

if (this.wasConnectedToCDP) {
      this.vscSession && debug.stopDebugging(this.vscSession);
      await this.startDebugSession();
    }

Copy link
Member

@kmagiera kmagiera left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if it would be possible to start the main JS debugger as child session and have the metro DebugAdapter as a separate concept. We could use debug.startDebugging parentSession parameter for that. Maybe, when it is setup this way the session would share the console? Idk

@filip131311
Copy link
Collaborator Author

@kmagiera I tested the approach with a parent debugger, with de following code:

const parentDebugger = await debug.startDebugging( undefined,
      {
        type: "com.swmansion.react-native-debugger",
        name: "Radon IDE Debugger 22",
        request: "attach",
      },
      {
        suppressDebugStatusbar: true,
        suppressDebugView: true,
        suppressDebugToolbar: true,
        suppressSaveBeforeStart: true,
      });
    const activeDebugSession = debug.activeDebugSession;
    const debugStarted = await debug.startDebugging(
      undefined,
      {
        type: "com.swmansion.react-native-debugger",
        name: "Radon IDE Debugger",
        request: "attach",
      },
      {
        parentSession: activeDebugSession ,
        suppressDebugStatusbar: true,
        suppressDebugView: true,
        suppressDebugToolbar: true,
        suppressSaveBeforeStart: true,
      }
    );

    if (debugStarted) {
      this.vscSession = debug.activeDebugSession!;
.
.
.

and unfortunatally the result was the same as when we didn't use parent debugger configuration. Both debuggers were still selectable by a user, which introduces a risk of the wrong one being selected, and whats worse would split the output of bundle errors and application logs.

image

Copy link
Member

@kmagiera kmagiera left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a couple more comments inline. Also, I wonder if this change won't conflict with #985 (I imagine it would, but I'd hope we can resolve it rather easily)

Comment on lines 30 to 31
| "bundleError"
| "incrementalBundleError"
| "bundlingError"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can't have both bundleError and bundlingError, how do you tell which one means what?

await this.session.customRequest("RNIDE_connect_cdp_debugger", cdpConfiguration);
}

public async sendDebugConsoleLog(message: string, source?: DebugSource) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"send" doesn't feel right as we are not sending logs. This should rather be "append". Also I believe we should actually report this as "error" and not "log". So maybe this should be appendDebuggerConsoleEntry or writeToDebuggerConsole and the method should also take the category of the entry (log/warning/error etc)

});
}

public async startDebugSession() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we are mixing up names here which makes this change very confusing. Sometime we refer to the connection with JS debugger as JSDebugger and at other times we use DebugSession. I think we should just keep using start here and in places where we explicitely deal with the CDP JS debugger, we should use JSDebugger

Comment on lines 94 to 95
this.debugSession = new DebugSession(this.debugEventDelegate);
this.debugSession.startDebugSession();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should avoid exposing too many unnecessary implementation details. If this isn't useful to have separate control over creating and starting, the constructor should just start the session on its own.

Comment on lines 107 to 108
await this.debugSession.stopDebugSession();
await this.debugSession.startDebugSession();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similatily here, I understand that we are referring to JS debugger here. We don't need to leak the implementation details here. If we want to have a signal that the session needs to be cleared, we should expose a mathod for that and the session on its own will decide that it should restart the JS debugger connection.

this.debugSession = new DebugSession(this.metro, this.debugEventDelegate);
const started = await this.debugSession.start();
if (started) {
private async connectDebugger() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets be consistent and use JSDebugger here. We have too many things called debugger or debug session already.

@filip131311 filip131311 requested a review from kmagiera February 27, 2025 19:38
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 this pull request may close these issues.

2 participants