How Lightpanda Implements JavaScript Execution via the CDP Runtime Domain
Lightpanda executes JavaScript through the CDP Runtime domain by routing Runtime.evaluate commands from the CDP dispatcher through a V8 inspector session to the Zig-based Local.compileAndRun function, which compiles and executes scripts using V8's ScriptCompiler API.
Lightpanda is a lightweight, Zig-based browser engine that implements the Chrome DevTools Protocol (CDP) to enable remote debugging and automation. Its JavaScript execution capabilities are exposed through the CDP Runtime domain, providing full compatibility with standard DevTools clients while leveraging the V8 JavaScript engine embedded within its architecture.
Architecture Overview of Lightpanda JavaScript Execution
The implementation spans multiple layers, from CDP message parsing to V8 script compilation.
CDP Runtime Domain Entry Point
The Runtime domain dispatcher resides in src/cdp/domains/runtime.zig. The processMessage function maps incoming action strings (such as "evaluate") to internal enums. For actions other than runIfWaitingForDebugger, it invokes sendInspector to forward the request.
Inspector Session Routing
The sendInspector function retrieves the current BrowserContext and forwards the raw CDP JSON payload to the inspector session via bc.callInspector. This function, defined in src/cdp/cdp.zig, writes the message to the V8 inspector and immediately triggers runMicrotasks() to process the command.
Tool Handler Integration
The actual JavaScript execution is handled as a tool in src/mcp/tools.zig. The handleEvaluate function receives the EvaluateParams, obtains the current page's JavaScript context, and prepares the execution environment before invoking the V8 binding layer.
Execution Flow from CDP to V8
The complete execution path transforms a CDP command into a V8 script evaluation:
- Client Request: The DevTools client sends a
Runtime.evaluatecommand:
{
"jsonrpc": "2.0",
"id": 1,
"method": "Runtime.evaluate",
"params": {
"expression": "2 + 2"
}
}
-
CDP Parsing:
runtime.processMessageinsrc/cdp/domains/runtime.zigidentifies the action as.evaluateand callssendInspector. -
Inspector Forwarding: The
callInspectormethod insrc/cdp/cdp.zigpasses the JSON to the V8 inspector session and runs microtasks. -
Tool Dispatch: The inspector routes to
handleEvaluateinsrc/mcp/tools.zig, which:- Parses
EvaluateParams(script and optional URL) - Optionally navigates to a URL first (
performGoto) - Retrieves the current page (
server.session.currentPage) - Creates a
js.Local.Scopefor the page's JavaScript context - Sets up
js.TryCatchto capture V8 exceptions
- Parses
-
V8 Compilation:
handleEvaluatecallsls.local.compileAndRun(args.script, null)defined insrc/browser/js/Local.zig. This function:- Builds a V8
ScriptOriginandScriptCompilerSource - Calls
v8__ScriptCompiler__Compileto compile the source - Executes via
v8__Script__Run - Returns a
js.Valuewrapping the V8 handle
- Builds a V8
-
Module Evaluation: For ES modules,
src/browser/js/Module.zigprovidesmodule.evaluate(), used internally by theLocalAPIs when a script imports modules. -
Response Serialization: The result is converted to a string (
js_result.toStringSliceWithAlloc) and wrapped in a CDP-compliant JSON response:
{
"id": 1,
"result": {
"value": "4"
}
}
Error Handling and Exception Management
Lightpanda captures JavaScript exceptions using V8's TryCatch mechanism before they propagate back to the CDP client.
In src/mcp/tools.zig, the handleEvaluate function wraps the compileAndRun call with js.TryCatch. If V8 throws an exception during compilation or execution, caught.format serializes the exception details. The response is then sent with .isError = true and the serialized error message, maintaining CDP compatibility for runtime exceptions.
Key Source Files and Functions
| Purpose | File Path | Key Functions |
|---|---|---|
| CDP Runtime domain dispatcher | src/cdp/domains/runtime.zig |
processMessage, sendInspector |
| Inspector session forwarding | src/cdp/cdp.zig |
callInspector |
| Tool handling for evaluation | src/mcp/tools.zig |
handleEvaluate, EvaluateParams |
| V8 script compilation/execution | src/browser/js/Local.zig |
compileAndRun |
| ES module evaluation | src/browser/js/Module.zig |
evaluate |
| Page context management | src/browser/Page.zig |
Context retrieval for JS scope |
| Browser environment | src/browser/Browser.zig |
Inspector and microtask management |
Summary
Lightpanda's JavaScript execution via the CDP Runtime domain follows a tightly integrated pipeline:
- CDP Runtime domain in
src/cdp/domains/runtime.zigparses incomingRuntime.evaluaterequests and forwards them to the V8 inspector session. - Inspector session in
src/cdp/cdp.zigroutes commands to the embedded V8 engine and triggers immediate microtask processing. - Tool handler in
src/mcp/tools.zigprepares the page context, sets up exception handling, and invokes the V8 binding layer. - V8 binding in
src/browser/js/Local.zigcompiles scripts usingScriptCompilerand executes them, returning results or capturing exceptions viajs.TryCatch.
This architecture enables Lightpanda to provide full CDP-compatible JavaScript evaluation, including ES module support, while maintaining the performance benefits of Zig and V8 integration.
Frequently Asked Questions
How does Lightpanda handle JavaScript exceptions during Runtime.evaluate?
Lightpanda wraps the V8 execution in a js.TryCatch block within the handleEvaluate function in src/mcp/tools.zig. If the script throws an exception, caught.format serializes the error details, and the response is sent with .isError = true to maintain CDP compatibility for error reporting.
What is the difference between Local.zig and Module.zig in Lightpanda's JavaScript execution?
src/browser/js/Local.zig provides the compileAndRun function for traditional script evaluation using V8's ScriptCompiler, while src/browser/js/Module.zig implements module.evaluate() for ES module execution. The Local APIs internally use Module functionality when scripts contain ES module imports.
How does Lightpanda ensure CDP compatibility for the Runtime domain?
Lightpanda implements the CDP Runtime domain by parsing standard CDP messages in src/cdp/domains/runtime.zig, forwarding them through the V8 inspector session in src/cdp/cdp.zig, and formatting responses according to the CDP specification in src/mcp/tools.zig. This ensures compatibility with standard DevTools clients and automation tools.
Where does the actual V8 script compilation happen in Lightpanda?
The actual V8 compilation occurs in src/browser/js/Local.zig within the compileAndRun function. This function constructs a V8 ScriptOrigin and ScriptCompilerSource, calls v8__ScriptCompiler__Compile to compile the source code, and then executes it via v8__Script__Run.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →