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

NodeJS 20 --import, --inspect-brk and Chrome DevTools don't work together (works in NodeJS 18) #53681

Closed
ajvincent opened this issue Jul 2, 2024 · 6 comments · Fixed by #54219
Labels
inspector Issues and PRs related to the V8 inspector protocol

Comments

@ajvincent
Copy link

Version

v20.15.0

Platform

Linux fedora 6.9.6-200.fc40.x86_64 #1 SMP PREEMPT_DYNAMIC Fri Jun 21 15:48:21 UTC 2024 x86_64 GNU/Linux

Subsystem

No response

What steps will reproduce the bug?

Google Chrome: Version 126.0.6478.126 (Official Build) (64-bit)
OS: Fedora Linux 40 (Workstation Edition)

  1. Create the following files:

loader-hooks/loader.js

export async function initialize() {
}

export async function resolve(specifier, context, nextResolve) {
  return nextResolve(specifier, context);
}

export async function load(url, context, nextLoad) {
  return nextLoad(url, context);
}

loader-hooks/registration.js

import url from 'node:url'
import { register } from 'node:module';

const __filename = url.fileURLToPath(import.meta.url);
register(`./loader.js`, url.pathToFileURL(__filename));

build.js

console.log("success");
  1. Install nvm, so you can switch between NodeJS 18 and NodeJS 20.
  2. Run the following commands from your directory:
nvm use 18
node --import ./loader-hooks/registration.js ./build.js
node --inspect-brk --import ./loader-hooks/registration.js ./build.js
  1. When the debugger for the last command is available, in Google Chrome, visit chrome://inspect/#devices . You should have a Target link for ./build.js available. Click it, and observe the Chrome DevTools window. The Play button should be active. You can hit Play and the debugging session will finish cleanly.

  2. Close the Chrome Developer Tools window, to terminate the debugging session.

  3. Run the following commands from your directory:

nvm use 20
node --import ./loader-hooks/registration.js ./build.js
node --inspect-brk --import ./loader-hooks/registration.js ./build.js
  1. Repeat step 4.

This time you will not have a Play button. The Developer Tools window is stuck, unable to proceed.

The only difference here is Node 20 versus Node 18.

How often does it reproduce? Is there a required condition?

Always.

What is the expected behavior? Why is that the expected behavior?

The Developer Tools in Google Chrome should be able to step through the code. This worked when using Node 18 as the debuggee.

What do you see instead?

No ability to step through code or inspect variables. The Developer Tools are unusable and the NodeJS process is presumably waiting for the Developer Tools to step forward..

Additional information

I do not know if this is a Google Chrome bug or a NodeJS bug. Somewhere between the two, the debugging handshake fails.

@ajvincent
Copy link
Author

node -v for Node 18 installed via nvm returns v18.20.0.

@ajvincent
Copy link
Author

As I mention in other tickets, this impacted me for both ts-node and tsimp usage.

@juanarbol
Copy link
Member

juanarbol commented Jul 2, 2024 via email

@RedYetiDev RedYetiDev added the inspector Issues and PRs related to the V8 inspector protocol label Jul 2, 2024
@STRd6
Copy link
Contributor

STRd6 commented Aug 1, 2024

I'm also hitting this issue. Essentially any call to the new register causes --inspect-brk to hang forever when attempting to connect dev tools.

Works in node 20.14.0 broken in 20.15.1

Clicking the pause button in Chrome dev tools reveals that it is stuck here:

  // node:internal/modules/esm/hooks
  
  // line 587
  waitForWorker() {
    if (!this.#isReady) {
      const { kIsOnline } = require('internal/worker');
      if (!this.#worker[kIsOnline]) {
        debug('wait for signal from worker');
        AtomicsWait(this.#lock, WORKER_TO_MAIN_THREAD_NOTIFICATION, 0); // <----- Paused on this line
        const response = this.#worker.receiveMessageSync();
        if (response == null || response.message.status === 'exit') { return; }
        const { preloadScripts } = this.#unwrapMessage(response);
        this.#executePreloadScripts(preloadScripts);
      }

      this.#isReady = true;
    }
  }

@STRd6
Copy link
Contributor

STRd6 commented Aug 1, 2024

Steps for simple reproduction:
11ty/eleventy#3371 (comment)

node --inspect-brk ./registerer.js

import module from "node:module";

module.register("./empty-file.js");

console.log( "DONE!" );

@magicdawn
Copy link

+1 when debug with tsx (which is --import tsx --inspect-brk)

and a method to mitigate:
use 2 debuggger, e.g

  1. start node --inspect-brk in vscode's JavaScript debug terminal
  2. open chrome devtools to attach.
  3. now 2 debugger attached(vscode & chrome devtools), when paused at where u want, u can close 1 now.

I don't know what happend, but this does works for me 😂

targos pushed a commit that referenced this issue Aug 14, 2024
Internal workers are essential to load user scripts and bootstrapped
with internal entrypoints. They should not be waiting for inspectors
even when `--inspect-brk` and `--inspect-wait` were specified, and avoid
blocking main thread to bootstrap.

IsolateData can be created with a specified PerIsolateOptions instead of
creating a copy from the per_process namespace. This also avoids
creating a copy bypassing the parent env's modified options, like
creating a worker thread from a worker thread.

PR-URL: #54219
Fixes: #53681
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
targos pushed a commit that referenced this issue Sep 21, 2024
Internal workers are essential to load user scripts and bootstrapped
with internal entrypoints. They should not be waiting for inspectors
even when `--inspect-brk` and `--inspect-wait` were specified, and avoid
blocking main thread to bootstrap.

IsolateData can be created with a specified PerIsolateOptions instead of
creating a copy from the per_process namespace. This also avoids
creating a copy bypassing the parent env's modified options, like
creating a worker thread from a worker thread.

PR-URL: #54219
Fixes: #53681
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
targos pushed a commit that referenced this issue Sep 26, 2024
Internal workers are essential to load user scripts and bootstrapped
with internal entrypoints. They should not be waiting for inspectors
even when `--inspect-brk` and `--inspect-wait` were specified, and avoid
blocking main thread to bootstrap.

IsolateData can be created with a specified PerIsolateOptions instead of
creating a copy from the per_process namespace. This also avoids
creating a copy bypassing the parent env's modified options, like
creating a worker thread from a worker thread.

PR-URL: #54219
Fixes: #53681
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
targos pushed a commit that referenced this issue Oct 2, 2024
Internal workers are essential to load user scripts and bootstrapped
with internal entrypoints. They should not be waiting for inspectors
even when `--inspect-brk` and `--inspect-wait` were specified, and avoid
blocking main thread to bootstrap.

IsolateData can be created with a specified PerIsolateOptions instead of
creating a copy from the per_process namespace. This also avoids
creating a copy bypassing the parent env's modified options, like
creating a worker thread from a worker thread.

PR-URL: #54219
Fixes: #53681
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
inspector Issues and PRs related to the V8 inspector protocol
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants