GeezerVison is showing github.com — feat(inspector): attach Chrome DevTools to Web Worker isolates by edusperoni · Pull Request #386 · NativeScript/ios
Conversation
edusperoni
commented
Jun 11, 2026
•
edited by coderabbitai
Bot
Loading
Uh oh!
There was an error while loading. Please reload this page.
Workers were invisible to the debugger: the inspector only served the main isolate and even dropped worker console output on the floor. DevTools discovers extra isolates through the Target domain with flat-session multiplexing, so implement that surface in the runtime:
- Add WorkerInspectorClient: a per-worker V8Inspector + session that lives entirely on the worker's thread. Incoming CDP messages queue through a dedicated CFRunLoopSource on the worker's runloop; while paused at a breakpoint a nested loop on the worker thread pumps the same queue without re-entering the runloop, so postMessage deliveries stay queued during a pause (matching Chrome's semantics).
- Turn JsV8InspectorClient into the root session + router: handle Target.setAutoAttach natively (announce workers via Target.attachedToTarget, detach on death), route messages carrying a top-level sessionId to the worker's thread directly from the socket thread, and make the frontend sender thread-safe. Routing off the socket thread means a worker stays debuggable while the main isolate is paused, and vice versa.
- Debugger.pause for a busy worker uses RequestInterrupt keyed by workerId, so a late-firing interrupt after worker death is a no-op. This also fixes the main-session fast path, which used to interrupt the main isolate for a pause aimed at any session.
- Serve Network.loadNetworkResource and IO.read/IO.close on the socket thread for any session (sessionId echoed), so worker source maps load too.
- Route worker console.* to the worker's own inspector and deliver through V8ConsoleMessageStorage::addMessage instead of the live-only runtime agent path: messages logged before the frontend attaches (or before Runtime.enable reaches a session) are stored and replayed as console history. Applies to the main isolate as well.
- Name execution contexts ("main" / worker script url) so the DevTools console context selector rows are labeled and selectable.
- Worker lifecycle: inspector is created on the worker thread before RunModule (debug builds only), terminate() kicks a paused worker out of its nested pause loop, teardown unregisters the target before the isolate is disposed, and frontend reconnects reset worker sessions.
waitForDebuggerOnStart (pause new workers before their first line) is left as future work; workers currently announce waitingForDebugger: false.
Summary by CodeRabbit
-
New Features
- Worker threads are visible and debuggable in Chrome DevTools as child targets, with session-aware routing so messages, network/resource fetches, and console logs map to the correct worker/front-end session.
- Workers auto-attach/discover for unified debugging and support pause requests from the frontend.
-
Bug Fixes
- Improved thread-safety and reliable pause/resume/teardown across main and worker runtimes.
-
Chores
- Build configuration updated to include worker inspector sources.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Workers were invisible to the debugger: the inspector only served the
main isolate and even dropped worker console output on the floor.
DevTools discovers extra isolates through the Target domain with
flat-session multiplexing, so implement that surface in the runtime:
- Add WorkerInspectorClient: a per-worker V8Inspector + session that
lives entirely on the worker's thread. Incoming CDP messages queue
through a dedicated CFRunLoopSource on the worker's runloop; while
paused at a breakpoint a nested loop on the worker thread pumps the
same queue without re-entering the runloop, so postMessage deliveries
stay queued during a pause (matching Chrome's semantics).
- Turn JsV8InspectorClient into the root session + router: handle
Target.setAutoAttach natively (announce workers via
Target.attachedToTarget, detach on death), route messages carrying a
top-level sessionId to the worker's thread directly from the socket
thread, and make the frontend sender thread-safe. Routing off the
socket thread means a worker stays debuggable while the main isolate
is paused, and vice versa.
- Debugger.pause for a busy worker uses RequestInterrupt keyed by
workerId, so a late-firing interrupt after worker death is a no-op.
This also fixes the main-session fast path, which used to interrupt
the main isolate for a pause aimed at any session.
- Serve Network.loadNetworkResource and IO.read/IO.close on the socket
thread for any session (sessionId echoed), so worker source maps
load too.
- Route worker console.* to the worker's own inspector and deliver
through V8ConsoleMessageStorage::addMessage instead of the live-only
runtime agent path: messages logged before the frontend attaches (or
before Runtime.enable reaches a session) are stored and replayed as
console history. Applies to the main isolate as well.
- Name execution contexts ("main" / worker script url) so the DevTools
console context selector rows are labeled and selectable.
- Worker lifecycle: inspector is created on the worker thread before
RunModule (debug builds only), terminate() kicks a paused worker out
of its nested pause loop, teardown unregisters the target before the
isolate is disposed, and frontend reconnects reset worker sessions.
waitForDebuggerOnStart (pause new workers before their first line) is
left as future work; workers currently announce waitingForDebugger:
false.
coderabbitai
Bot
commented
Jun 11, 2026
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
|

No actionable comments were generated in the recent review. 🎉
ℹ️ Recent review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 8759c6d7-268c-4e74-bc67-36a99eea5190
📥 Commits
Reviewing files that changed from the base of the PR and between b0f3439 and 026e407.
📒 Files selected for processing (1)
NativeScript/inspector/JsV8InspectorClient.mm
🚧 Files skipped from review as they are similar to previous changes (1)
- NativeScript/inspector/JsV8InspectorClient.mm
📝 Walkthrough
Walkthrough
Adds worker-target DevTools support: main inspector routes session-scoped messages, a WorkerInspectorClient owns per-worker V8 inspector sessions and pause loops, network/IO handlers become session-aware, console logs are forwarded per-worker, and worker inspectors are created/destroyed during worker lifecycle.
Changes
Worker Inspector Support
| Layer / File(s) |
Summary |
Main Inspector Client API & Threading Foundation NativeScript/inspector/JsV8InspectorClient.h, NativeScript/inspector/JsV8InspectorClient.mm |
Introduces singleton GetInstance(), SendToFrontend, worker-target registration/pause APIs, mutex-protected sender/resource/worker maps, and instance initialization. |
Session Routing & Worker Target Discovery NativeScript/inspector/JsV8InspectorClient.mm |
Fast-parses frontend messages to extract sessionId/method/id, routes session-bearing messages to worker targets via RouteToWorker, handles Target domain auto-attach/discovery semantics, and resets worker state on disconnect. |
Session-Aware Network Resource Handling NativeScript/inspector/JsV8InspectorClient.mm |
HandleLoadNetworkResource, HandleIORead, HandleIOClose accept sessionId, use resourceStreamsMutex_ for stream lifecycle, and send session-scoped replies/errors. |
Frontend Messaging & Worker Console Integration NativeScript/inspector/JsV8InspectorClient.mm |
Adds SendToFrontend (sender mutex + source-map rewrite), forwards worker isolate console logs to WorkerInspectorClient, and stores main-isolate console messages for replay/history. |
WorkerInspectorClient Type & Initialization NativeScript/inspector/WorkerInspectorClient.h, NativeScript/inspector/WorkerInspectorClient.mm |
New WorkerInspectorClient: per-worker IDs/session, CFRunLoop source and semaphore for draining incoming CDP messages, V8Inspector/session/context initialization, and thread-safe incoming queue. |
Worker Protocol Dispatch & Pause Management NativeScript/inspector/WorkerInspectorClient.mm |
Dispatch pipeline with session reset coordination, nested pause-loop pumping, isolate-interrupt pause scheduling, wrapping outgoing messages with sessionId, and worker console message storage. |
Worker Runtime Lifecycle Integration NativeScript/runtime/DataWrapper.h, NativeScript/runtime/Worker.mm, NativeScript/runtime/WorkerWrapper.mm |
Adds CreateInspector()/DestroyInspector() to WorkerWrapper, creates the inspector before running the worker module, notifies inspector on termination to break pause loops, and destroys inspector during cleanup under inspectorMutex_. |
Xcode Build System Integration v8ios.xcodeproj/project.pbxproj |
Adds WorkerInspectorClient.h and WorkerInspectorClient.mm to project file references, build phases, and the inspector group. |
Estimated code review effort
🎯 4 (Complex) | ⏱️ ~60 minutes
Possibly related PRs
- NativeScript/ios#385: Modifies DevTools resource IO handling and stream bookkeeping; closely related to the session-aware resource changes here.
- NativeScript/ios#378: Adds V8 interrupt behavior for
Debugger.pause; related to the pause-scheduling/interrupt logic in worker handling.
Suggested reviewers
Poem
🐰 I hop through threads with tiny paws,
I wrap your sessions, mind the pause,
Workers whisper to DevTools bright,
Messages routed, consoles light,
Debugging carrots—what a sight!
🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
| Check name |
Status |
Explanation |
Resolution |
| Docstring Coverage |
⚠️ Warning |
Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. |
Write docstrings for the functions missing them to satisfy the coverage threshold. |
✅ Passed checks (4 passed)
| Check name |
Status |
Explanation |
| Description Check |
✅ Passed |
Check skipped - CodeRabbit’s high-level summary is enabled. |
| Title check |
✅ Passed |
The title directly and accurately describes the main change: adding Chrome DevTools support for Web Worker isolates as separate targets with per-worker inspector sessions. |
| Linked Issues check |
✅ Passed |
Check skipped because no linked issues were found for this pull request. |
| Out of Scope Changes check |
✅ Passed |
Check skipped because no linked issues were found for this pull request. |
✏️ Tip: You can configure your own custom pre-merge checks in the settings.
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
❤️ Share
Comment @coderabbitai help to get the list of available commands and usage tips.
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
This was referenced Aug 12, 2026
Uh oh!
There was an error while loading. Please reload this page.
Assignees
No one assigned
Milestone
No milestone
Development
Successfully merging this pull request may close these issues.
Uh oh!
There was an error while loading. Please reload this page.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
|