Skip to content

Commit 8748dd6

Browse files
cola119targos
authored andcommitted
inspector: introduce the --inspect-wait flag
PR-URL: #52734 Reviewed-By: Daeyeon Jeong <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Minwoo Jung <[email protected]>
1 parent 4f96b00 commit 8748dd6

File tree

7 files changed

+90
-10
lines changed

7 files changed

+90
-10
lines changed

doc/api/cli.md

+16
Original file line numberDiff line numberDiff line change
@@ -1270,6 +1270,7 @@ Activate inspector on `host:port`. Default is `127.0.0.1:9229`.
12701270
V8 inspector integration allows tools such as Chrome DevTools and IDEs to debug
12711271
and profile Node.js instances. The tools attach to Node.js instances via a
12721272
tcp port and communicate using the [Chrome DevTools Protocol][].
1273+
See [V8 Inspector integration for Node.js][] for further explanation on Node.js debugger.
12731274

12741275
<!-- Anchor to make sure old links find a target -->
12751276

@@ -1300,6 +1301,8 @@ added: v7.6.0
13001301
Activate inspector on `host:port` and break at start of user script.
13011302
Default `host:port` is `127.0.0.1:9229`.
13021303

1304+
See [V8 Inspector integration for Node.js][] for further explanation on Node.js debugger.
1305+
13031306
### `--inspect-port=[host:]port`
13041307

13051308
<!-- YAML
@@ -1321,6 +1324,17 @@ Specify ways of the inspector web socket url exposure.
13211324
By default inspector websocket url is available in stderr and under `/json/list`
13221325
endpoint on `http://host:port/json/list`.
13231326

1327+
### `--inspect-wait[=[host:]port]`
1328+
1329+
<!-- YAML
1330+
added: REPLACEME
1331+
-->
1332+
1333+
Activate inspector on `host:port` and wait for debugger to be attached.
1334+
Default `host:port` is `127.0.0.1:9229`.
1335+
1336+
See [V8 Inspector integration for Node.js][] for further explanation on Node.js debugger.
1337+
13241338
### `-i`, `--interactive`
13251339

13261340
<!-- YAML
@@ -2709,6 +2723,7 @@ one is included in the list below.
27092723
* `--inspect-brk`
27102724
* `--inspect-port`, `--debug-port`
27112725
* `--inspect-publish-uid`
2726+
* `--inspect-wait`
27122727
* `--inspect`
27132728
* `--max-http-header-size`
27142729
* `--napi-modules`
@@ -3205,6 +3220,7 @@ node --stack-trace-limit=12 -p -e "Error.stackTraceLimit" # prints 12
32053220
[ScriptCoverage]: https://chromedevtools.github.io/devtools-protocol/tot/Profiler#type-ScriptCoverage
32063221
[ShadowRealm]: https://github.com/tc39/proposal-shadowrealm
32073222
[Source Map]: https://sourcemaps.info/spec.html
3223+
[V8 Inspector integration for Node.js]: debugger.md#v8-inspector-integration-for-nodejs
32083224
[V8 JavaScript code coverage]: https://v8project.blogspot.com/2017/12/javascript-code-coverage.html
32093225
[V8 code cache]: https://v8.dev/blog/code-caching-for-devs
32103226
[Web Crypto API]: webcrypto.md

doc/api/debugger.md

+15-2
Original file line numberDiff line numberDiff line change
@@ -234,8 +234,21 @@ V8 Inspector can be enabled by passing the `--inspect` flag when starting a
234234
Node.js application. It is also possible to supply a custom port with that flag,
235235
e.g. `--inspect=9222` will accept DevTools connections on port 9222.
236236

237-
To break on the first line of the application code, pass the `--inspect-brk`
238-
flag instead of `--inspect`.
237+
Using the `--inspect` flag will execute the code immediately before debugger is connected.
238+
This means that the code will start running before you can start debugging, which might
239+
not be ideal if you want to debug from the very beginning.
240+
241+
In such cases, you have two alternatives:
242+
243+
1. `--inspect-wait` flag: This flag will wait for debugger to be attached before executing the code.
244+
This allows you to start debugging right from the beginning of the execution.
245+
2. `--inspect-brk` flag: Unlike `--inspect`, this flag will break on the first line of the code
246+
as soon as debugger is attached. This is useful when you want to debug the code step by step
247+
from the very beginning, without any code execution prior to debugging.
248+
249+
So, when deciding between `--inspect`, `--inspect-wait`, and `--inspect-brk`, consider whether you want
250+
the code to start executing immediately, wait for debugger to be attached before execution,
251+
or break on the first line for step-by-step debugging.
239252

240253
```console
241254
$ node --inspect index.js

doc/node.1

+5
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,11 @@ and
281281
Default is
282282
.Sy stderr,http .
283283
.
284+
.It Fl -inspect-wait Ns = Ns Ar [host:]port
285+
Activate inspector on
286+
.Ar host:port
287+
and wait for debugger to be attached.
288+
.
284289
.It Fl -inspect Ns = Ns Ar [host:]port
285290
Activate inspector on
286291
.Ar host:port .

src/inspector_agent.cc

+12-8
Original file line numberDiff line numberDiff line change
@@ -743,20 +743,24 @@ bool Agent::Start(const std::string& path,
743743
}, parent_env_);
744744

745745
bool wait_for_connect = options.wait_for_connect();
746+
bool should_break_first_line = options.should_break_first_line();
746747
if (parent_handle_) {
747-
wait_for_connect = parent_handle_->WaitForConnect();
748-
parent_handle_->WorkerStarted(client_->getThreadHandle(), wait_for_connect);
748+
should_break_first_line = parent_handle_->WaitForConnect();
749+
parent_handle_->WorkerStarted(client_->getThreadHandle(),
750+
should_break_first_line);
749751
} else if (!options.inspector_enabled || !options.allow_attaching_debugger ||
750752
!StartIoThread()) {
751753
return false;
752754
}
753755

754-
// Patch the debug options to implement waitForDebuggerOnStart for
755-
// the NodeWorker.enable method.
756-
if (wait_for_connect) {
757-
CHECK(!parent_env_->has_serialized_options());
758-
debug_options_.EnableBreakFirstLine();
759-
parent_env_->options()->get_debug_options()->EnableBreakFirstLine();
756+
if (wait_for_connect || should_break_first_line) {
757+
// Patch the debug options to implement waitForDebuggerOnStart for
758+
// the NodeWorker.enable method.
759+
if (should_break_first_line) {
760+
CHECK(!parent_env_->has_serialized_options());
761+
debug_options_.EnableBreakFirstLine();
762+
parent_env_->options()->get_debug_options()->EnableBreakFirstLine();
763+
}
760764
client_->waitForFrontend();
761765
}
762766
return true;

src/node_options.cc

+8
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,14 @@ DebugOptionsParser::DebugOptionsParser() {
331331
Implies("--inspect-brk-node", "--inspect");
332332
AddAlias("--inspect-brk-node=", { "--inspect-port", "--inspect-brk-node" });
333333

334+
AddOption(
335+
"--inspect-wait",
336+
"activate inspector on host:port and wait for debugger to be attached",
337+
&DebugOptions::inspect_wait,
338+
kAllowedInEnvvar);
339+
Implies("--inspect-wait", "--inspect");
340+
AddAlias("--inspect-wait=", {"--inspect-port", "--inspect-wait"});
341+
334342
AddOption("--inspect-publish-uid",
335343
"comma separated list of destinations for inspector uid"
336344
"(default: stderr,http)",

src/node_options.h

+6
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ class DebugOptions : public Options {
7171
bool allow_attaching_debugger = true;
7272
// --inspect
7373
bool inspector_enabled = false;
74+
// --inspect-wait
75+
bool inspect_wait = false;
7476
// --debug
7577
bool deprecated_debug = false;
7678
// --inspect-brk
@@ -93,6 +95,10 @@ class DebugOptions : public Options {
9395
}
9496

9597
bool wait_for_connect() const {
98+
return break_first_line || break_node_first_line || inspect_wait;
99+
}
100+
101+
bool should_break_first_line() const {
96102
return break_first_line || break_node_first_line;
97103
}
98104

test/parallel/test-inspector-wait.mjs

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import * as common from '../common/index.mjs';
2+
3+
common.skipIfInspectorDisabled();
4+
5+
import assert from 'node:assert';
6+
import { NodeInstance } from '../common/inspector-helper.js';
7+
8+
9+
async function runTests() {
10+
const child = new NodeInstance(['--inspect-wait=0'], 'console.log(0);');
11+
const session = await child.connectInspectorSession();
12+
await session.send({ method: 'NodeRuntime.enable' });
13+
await session.waitForNotification('NodeRuntime.waitingForDebugger');
14+
15+
// The execution should be paused until the debugger is attached
16+
while (await child.nextStderrString() !== 'Debugger attached.');
17+
18+
await session.send({ 'method': 'Runtime.runIfWaitingForDebugger' });
19+
20+
// Wait for the execution to finish
21+
while (await child.nextStderrString() !== 'Waiting for the debugger to disconnect...');
22+
23+
await session.send({ method: 'NodeRuntime.disable' });
24+
session.disconnect();
25+
assert.strictEqual((await child.expectShutdown()).exitCode, 0);
26+
}
27+
28+
runTests().then(common.mustCall());

0 commit comments

Comments
 (0)