Skip to content

feat: Support CDP evaluation in Web Worker contexts #312

Description

@glamberson

Use Case

I'm building a performance testing tool for a WASM application that runs its core logic in a Web Worker. The Worker uses WebCodecs VideoDecoder for H.264 decode and exposes metrics via a JS API. I need to:

  1. Detect Worker targets when they spawn
  2. Evaluate JavaScript in the Worker context to read performance metrics
  3. Optionally listen for console messages from Workers

This is a common pattern for any application using Web Workers: PWAs, video players, WASM-heavy apps, etc.

Current Behavior

chromiumoxide currently cannot interact with Worker targets:

  1. Service workers are auto-detached: on_event() in handler/target.rs immediately detaches "service_worker" targets on attachment
  2. Non-page targets skip initialization: poll() returns None for !self.is_page(), so Workers never reach Initialized state
  3. No public API for Worker sessions: Browser::execute() sends with session_id: None (browser-level only)

The TargetType enum already has ServiceWorker, SharedWorker, and BackgroundPage variants with is_*() methods, suggesting this was anticipated but not implemented.

How Puppeteer/Playwright Handle This

Both tools implement Worker evaluation using standard CDP:

Target.setAutoAttach { autoAttach: true, flatten: true, waitForDebuggerOnStart: false }
  -> attachedToTarget event (targetInfo.type == "worker")
  -> sessionId for the Worker
  -> Runtime.evaluate on that sessionId

Chrome CDP fully supports this. The limitation is purely in chromiumoxide's abstraction layer.

Proposed Changes

  1. Remove auto-detach for service workers in on_event(), or make it configurable
  2. Generalize poll() initialization: allow non-page targets to reach a basic Initialized state (they don't need frame/network/emulation init, just Runtime)
  3. Expose Worker session API, something like:
// Get Worker targets
let workers = page.workers().await?;

// Evaluate JS in a Worker
let result = worker.evaluate("self.performance_stats()").await?;

The internal transport already supports session routing via CommandMessage::with_session(). The session_id flows correctly through conn.rs. The change is in the public API surface and initialization pipeline.

Alternatives Considered

  • MessageChannel bridge: Worker posts to main page, evaluate on page context. Works but adds latency and indirection.
  • Raw WebSocket to CDP: bypass chromiumoxide entirely for Worker commands. Works but defeats the purpose of using the library.
  • Fork: would rather contribute upstream if there's interest.

Environment

  • chromiumoxide v0.9.1
  • Chrome 133+
  • Using Workers for WASM (wasm-bindgen) with WebCodecs VideoDecoder

Happy to submit a PR if there's interest in this feature.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions