Skip to content

fix: return JS eval results on Windows/WebView2 (execute_js/dom_snapshot/screenshot time out)#29

Open
NicolasArnouts wants to merge 1 commit into
hypothesi:mainfrom
NicolasArnouts:fix/windows-webview2-eval-callback
Open

fix: return JS eval results on Windows/WebView2 (execute_js/dom_snapshot/screenshot time out)#29
NicolasArnouts wants to merge 1 commit into
hypothesi:mainfrom
NicolasArnouts:fix/windows-webview2-eval-callback

Conversation

@NicolasArnouts

Copy link
Copy Markdown

Problem

On Windows (WebView2), every webview tool that returns a value — webview_execute_js, webview_dom_snapshot, and the html2canvas / Screen-Capture webview_screenshot fallbacks — fails with WebView execution failed: Request timeout after 2000ms. The WebSocket transport and all Rust-native commands (ipc_get_backend_state, manage_window, …) work fine; only the JS-eval result round-trip hangs.

Root cause

execute_js forks by OS. macOS uses native WKWebView evaluateJavaScript:completionHandler: — added precisely because "the eval-and-IPC-callback approach … fails on some setups." Every other platform falls through to eval_with_ipc_callback, which runs a fire-and-forget window.eval() whose wrapper posts the result back via window.__TAURI__.core.invoke('plugin:mcp-bridge|script_result', …). On WebView2 that postback never completes, and the wrapper's .catch swallows the failure without falling through to the event.emit backup — so the Rust oneshot never resolves and the server's 2000 ms handshake (waitForResolveRefHelper) times out.

In other words, #12 was not macOS-specific — the same IPC-callback path also fails on Windows/WebView2; it was only worked around for macOS.

Fix

Route synchronous scripts on non-macOS through Tauri's WebviewWindow::eval_with_callback, which hands the JSON-serialized result back through WebView2's ICoreWebView2::ExecuteScript completion handler (WebKitGTK on Linux) — a real result channel with no JS→IPC postback, the cross-platform analogue of the macOS native path. Async/Promise scripts keep the existing eval_with_ipc_callback fallback, since the callback only captures the script's synchronous return value.

  • macOS behavior is unchanged (the new code is #[cfg(not(target_os = "macos"))]).
  • Returns the same { success, data } / { success, error } shape as the macOS path.

Verification

Built and run on Windows 11 (WebView2, Tauri 2.11.2) against a real Tauri app, via a local path-override of the crate:

  • execute_js → returns values (e.g. ok:complete:…:tauri=true)
  • dom_snapshot → full element tree with refs
  • screenshot → native capture succeeds
  • read_logs console → works

All four previously timed out at 2000 ms.

Related to #12 (extends that macOS fix to Windows/Linux).

🤖 Generated with Claude Code

The non-macOS execute_js path returns results through a JS->IPC postback
(invoke('plugin:mcp-bridge|script_result')) that never completes on WebView2,
so execute_js / dom_snapshot / the html2canvas screenshot fallback all time
out at the server's handshake. This is the same failure class that hypothesi#12 fixed
for macOS by switching to native evaluateJavaScript:completionHandler:.

Route synchronous scripts on non-macOS through Tauri's
WebviewWindow::eval_with_callback, which returns the result via WebView2's
ExecuteScript completion handler (WebKitGTK on Linux) with no JS postback —
the cross-platform analogue of the macOS native path. Async/Promise scripts
keep the existing IPC-callback fallback, since the callback only captures the
script's synchronous return value.

Verified on Windows 11 (WebView2, Tauri 2.11.2): execute_js, dom_snapshot,
and screenshot all return correctly where they previously timed out.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant