[WEP] keep WebViews running while hidden - #5920
Conversation
WalkthroughThis proposal defines an opt-in, per-window ChangesKeep Running When Hidden
Estimated code review effort: 1 (Trivial) | ~5 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
v3/wep/proposals/keep-running-when-hidden/proposal.md (1)
162-171: 🎯 Functional Correctness | 🔵 Trivial | 🏗️ Heavy liftExpand the acceptance tests to cover the full visibility state machine.
Add tests for:
- macOS
true,false, and unset values.- A WebView attached to a hidden or miniaturized
NSWindow.- macOS versions older than 14.
- Windows windows hidden before first display.
- Windows windows shown, then hidden or minimized, then restored.
- Default behavior with the option disabled.
- Public-option to native-bridge propagation.
The optional example can supplement these tests, but it cannot replace regression coverage.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@v3/wep/proposals/keep-running-when-hidden/proposal.md` around lines 162 - 171, Expand the proposal’s Test Plan to require regression coverage for the complete visibility state machine: macOS true, false, and unset options; WebViews in hidden or miniaturized NSWindows; macOS versions before 14; Windows windows hidden before first display; windows shown, then hidden or minimized, and restored; disabled-option defaults; and propagation from the public option through the native bridge. Treat the v3 example as optional supplementary coverage, not a substitute for these tests.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@v3/wep/proposals/keep-running-when-hidden/proposal.md`:
- Around line 15-18: Update the macOS proposal contract to use
WKInactiveSchedulingPolicySuspend instead of “OS default (automatic)”, and
describe KeepRunningWhenHidden as assigned while constructing
WKWebViewConfiguration before allocation rather than “at navigation time”.
Verify that the none policy actually prevents throttling for hidden NSWindow
content before exposing the option; otherwise revise or remove the macOS
exposure.
- Around line 26-27: Align the Windows preference wording with its
implementation: either update the hidden-window behavior to keep the WebView2
controller visible across later hide, minimize, and restore transitions, or
explicitly scope the option to windows that are hidden and have never been
shown. Update the Windows option description in the proposal so it matches the
chosen contract.
---
Nitpick comments:
In `@v3/wep/proposals/keep-running-when-hidden/proposal.md`:
- Around line 162-171: Expand the proposal’s Test Plan to require regression
coverage for the complete visibility state machine: macOS true, false, and unset
options; WebViews in hidden or miniaturized NSWindows; macOS versions before 14;
Windows windows hidden before first display; windows shown, then hidden or
minimized, and restored; disabled-option defaults; and propagation from the
public option through the native bridge. Treat the v3 example as optional
supplementary coverage, not a substitute for these tests.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: b6a4e44b-db87-44ac-984b-27ee1d82e8e7
📒 Files selected for processing (1)
v3/wep/proposals/keep-running-when-hidden/proposal.md
| Add an opt-in per-window preference that stops the platform WebView from | ||
| throttling JavaScript while the window is hidden. It is exposed as | ||
| `Mac.WebviewPreferences.KeepRunningWhenHidden` on macOS and | ||
| `Windows.KeepRunningWhenHidden` on Windows. Default behaviour is unchanged. |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Repository files for proposal:"
git ls-files | grep -E 'v3/wep/proposals/keep-running-when-hidden|keep-running-when-hidden' || true
echo
echo "Proposal excerpt:"
if [ -f v3/wep/proposals/keep-running-when-hidden/proposal.md ]; then
nl -ba v3/wep/proposals/keep-running-when-hidden/proposal.md | sed -n '1,120p'
fi
echo
echo "Search for related identifiers:"
rg -n "KeepRunningWhenHidden|inactiveSchedulingPolicy|WKPreferences|SchedulingPolicy|KeepRunning|throttl|suspend|automatic|hidden|miniaturiz" . || trueRepository: wailsapp/wails
Length of output: 297
🌐 Web query:
Apple WKPreferences inactiveSchedulingPolicy WebViews not in window default suspend thrott none
💡 Result:
The inactiveSchedulingPolicy property in Apple's WKPreferences class is used to specify how a WKWebView handles tasks when it is not in a window, such as when it is in a background tab [1][2]. This policy is available for macOS 14.0+ and iOS 17.0+ [2]. The policy can be set to one of the following values, defined in the WKPreferences.InactiveSchedulingPolicy enumeration [3][2]: 1. suspend: This is the default policy [1]. The web view fully suspends tasks, pausing JavaScript execution and page layout when the web view is idle and detached from the view hierarchy [1][3][2]. 2. throttle: The web view limits processing (CPU-throttled) when idle, but does not fully suspend tasks [3][2]. 3. none: No special scheduling behavior is applied, allowing the web view to continue running normally even when idle [3][2]. Web views are generally exempted from these inactive scheduling policies if they are actively playing media, performing media capture, or engaging in other user-interactive activities [1][2].
Citations:
- 1: https://developer.apple.com/documentation/webkit/wkpreferences/inactiveschedulingpolicy-swift.property
- 2: https://github.com/WebKit/webkit/blob/main/Source/WebKit/UIProcess/API/Cocoa/WKPreferences.h
- 3: https://developer.apple.com/documentation/webkit/wkpreferences/inactiveschedulingpolicy-swift.enum
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Proposal excerpt:"
awk '{printf "%6d\t%s\n", NR, $0}' v3/wep/proposals/keep-running-when-hidden/proposal.md | sed -n '1,140p'
echo
echo "Search for related identifiers:"
rg -n "KeepRunningWhenHidden|inactiveSchedulingPolicy|WKPreferences|SchedulingPolicy|KeepRunning|throttl|suspend|automatic|hidden|miniaturiz|window|attached|allocation|navigation" v3/wep/proposals/keep-running-when-hidden/proposal.md . || trueRepository: wailsapp/wails
Length of output: 50373
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Proposal excerpt:"
awk '{printf "%6d\t%s\n", NR, $0}' v3/wep/proposals/keep-running-when-hidden/proposal.md | sed -n '1,160p'
echo
echo "Exact identifier matches in proposal only:"
rg -n "KeepRunningWhenHidden|inactiveSchedulingPolicy|WKPreferences|SchedulingPolicy|KeepRunning|throttl|suspend|automatic|hidden|miniaturiz|window|at navigation time|allocation|navigation|true|false" v3/wep/proposals/keep-running-when-hidden/proposal.mdRepository: wailsapp/wails
Length of output: 11613
🌐 Web query:
Apple WKPreferences inactiveScheduling policy on hidden NSWindow WKWebView not no window
💡 Result:
The inactiveSchedulingPolicy property in WKPreferences allows developers to control the scheduling behavior of a WKWebView when it is idle and detached from the view hierarchy (i.e., not in a window) [1][2]. Introduced in macOS 14.0 and iOS 17.0, this policy addresses issues where WebKit might aggressively throttle or suspend the WebContent process for web views that are hidden or not currently attached to a window [1][3][4]. The policy provides three modes defined by the WKPreferences.InactiveSchedulingPolicy enumeration [5][1]: 1. WKInactiveSchedulingPolicyNone: The web view runs tasks normally, with no special scheduling behavior applied, even when idle [1]. This is often used to prevent unwanted suspension of background processes or web views that are meant to stay active while hidden [3][4]. 2. WKInactiveSchedulingPolicyThrottle: The web view CPU-throttles tasks when idle but does not fully suspend them [1]. 3. WKInactiveSchedulingPolicySuspend: The web view fully suspends tasks (pausing JavaScript execution and page layout) when idle [1]. Web views are generally not considered idle if they are currently playing media or loading web pages [1][6]. Developers typically use the None policy when they need to ensure that a WKWebView continues to execute JavaScript or maintain state while it is hidden or detached from a visible window [3][4].
Citations:
- 1: https://github.com/WebKit/webkit/blob/main/Source/WebKit/UIProcess/API/Cocoa/WKPreferences.h
- 2: https://developer.apple.com/documentation/webkit/wkpreferences
- 3: https://bugs.webkit.org/show_bug.cgi?format=multiple&id=263286
- 4: Adopt inactiveSchedulingPolicy for Web Extension background pages. WebKit/WebKit#19193
- 5: https://developer.apple.com/documentation/webkit/wkpreferences/inactiveschedulingpolicy-swift.enum
- 6: https://docs.rs/objc2-web-kit/latest/objc2_web_kit/struct.WKPreferences.html
Align the macOS contract with the API semantics.
WKPreferences.inactiveSchedulingPolicy is intended for WebViews idle and detached from the view hierarchy, not specifically for hidden NSWindow content. Verify that none prevents throttling for the hidden-window use case before exposing this option as described. Also replace “OS default (automatic)” with WKInactiveSchedulingPolicySuspend, and avoid “at navigation time” because the design says the value is assigned when the WKWebViewConfiguration is built before allocation.
[low_effort_and_medium_reward]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@v3/wep/proposals/keep-running-when-hidden/proposal.md` around lines 15 - 18,
Update the macOS proposal contract to use WKInactiveSchedulingPolicySuspend
instead of “OS default (automatic)”, and describe KeepRunningWhenHidden as
assigned while constructing WKWebViewConfiguration before allocation rather than
“at navigation time”. Verify that the none policy actually prevents throttling
for hidden NSWindow content before exposing the option; otherwise revise or
remove the macOS exposure.
Source: MCP tools
| - **Windows**: WebView2 moves a hidden window's controller into "efficiency | ||
| mode" (WebView2 issue #2861), driving the page's timers toward 0Hz. |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Changed files/stat:"
git diff --stat || true
echo
echo "Candidate proposal file:"
fd -a 'proposal\.md$' . | sed 's#^\./##' | grep -F 'v3/wep/proposals/keep-running-when-hidden/proposal.md' || true
echo
echo "Relevant proposal excerpt:"
if [ -f v3/wep/proposals/keep-running-when-hidden/proposal.md ]; then
nl -ba v3/wep/proposals/keep-running-when-hidden/proposal.md | sed -n '1,120p'
fi
echo
echo "Repository-wide references to keep-running/hidden/IsVisible:"
rg -n "keep-running|hidden|is_visible|IsVisible|WebView2|PutIsVisible|controller|efficiency" . --glob '!**/.git/**' --glob '!**/node_modules/**' --glob '!**/build/**' --glob '!**/dist/**' | head -n 200Repository: wailsapp/wails
Length of output: 340
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Changed files/stat:"
git diff --stat || true
echo
echo "Candidate proposal file:"
ls -la v3/wep/proposals/keep-running-when-hidden/proposal.md || true
echo
echo "Relevant proposal excerpt:"
awk '{printf "%6d\t%s\n", NR, $0}' v3/wep/proposals/keep-running-when-hidden/proposal.md | sed -n '1,140p'
echo
echo "Repository-wide references to keep-running/hidden/IsVisible:"
rg -n "keep-running|hidden|is_visible|IsVisible|WebView2|PutIsVisible|controller|efficiency" . --glob '!**/.git/**' --glob '!**/node_modules/**' --glob '!**/build/**' --glob '!**/dist/**' | head -n 200 || trueRepository: wailsapp/wails
Length of output: 50371
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Proposal excerpt:"
awk '{printf "%6d\t%s\n", NR, $0}' v3/wep/proposals/keep-running-when-hidden/proposal.md | sed -n '1,120p'
echo
echo "Focused source references for proposal keywords:"
rg -n -C 3 "KeepRunningWhenHidden|keep-running-when-hidden|KeepRunningWhenHidden|controller.|PutIsVisible|IsVisible|navigationCompleted|HideWindow|hide.*window|min.*window|restore.*window|window hidden|hidden.*window" v3 --glob '!**/*.md' --glob '!**/docs/**' | head -n 300
echo
echo "Candidate window/windowing files in v3:"
git ls-files v3 | rg '(^v3/.*/.*(window|browser|webview|window\.)|(^v3/.*/windows)' | sed -n '1,160p'Repository: wailsapp/wails
Length of output: 50372
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Focused Go references for windows WebViewOptions, KeepRunningWhenHidden, and PutIsVisible:"
rg -n -C 4 "KeepRunningWhenHidden|PutIsVisible|IsVisible|navigationCompleted|WebView.*Options|Webview.*Options|Chromium\\.(Show|Hide)|Show\\(\\)|Hide\\(" v3/internal v3/pkg v3/lib --glob '*.go' --max-count 200Repository: wailsapp/wails
Length of output: 50371
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Files containing KeepRunningWhenHidden (Go and proposal):"
rg -n "KeepRunningWhenHidden" . --glob '*.{go,md}' || true
echo
echo "Files containing WebviewWindowOptions + KeepRunningWhenHidden context:"
rg -n "KeepRunningWhenHidden|WebviewWindowOptions|type WindowsWindow|type WindowOptions|type .*Window " . --glob '*.go' | head -n 240
echo
echo "Windows window/windowing Go candidates:"
git ls-files v3 | rg 'windows|window|webview|webkit|platform|platforms|runtime' | head -n 220
echo
echo "webview2 window implementation candidates containing PutIsVisible or navigationCompleted:"
rg -n -C 5 "navigationCompleted|PutIsVisible|Hide\\(\\)|Show\\(|Hidden|WindowsWindow|KeepRunningWhenHidden|ICoreWebView2Controller3|ICoreWebView2Controller2" v3/internal/webview2 --glob '*.go' --max-count 200 || trueRepository: wailsapp/wails
Length of output: 35353
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "WindowsWindow option type and KeepRunningWhenHidden:"
awk '{printf "%6d\t%s\n", NR, $0}' v3/pkg/application/webview_window_options.go | sed -n '330,375p'
echo
echo "WindowsWebViewWindow field and constructor/options handling:"
awk '{printf "%6d\t%s\n", NR, $0}' v3/pkg/application/webview_window_windows.go | sed -n '1,180p'
rg -n -C 4 "navigationCompleted|PutIsVisible|IsVisible|Show\\(|Hide\\(|Hidden|W32|WWebView|windowsWebviewWindow|NewWithOptions|WebviewWindowOptions" v3/pkg/application/webview_window_windows.go | sed -n '1,260p'
echo
echo "WindowsWebViewWindow Hide.Show implementations nearby:"
awk '{printf "%6d\t%s\n", NR, $0}' v3/pkg/application/webview_window_windows.go | rg 'Hide|Show|Navigation|Controller|PutIsVisible|KeepRunningWhenHidden' -n -C 3 || trueRepository: wailsapp/wails
Length of output: 33417
🌐 Web query:
Microsoft WebView2 PutIsVisible IsVisible efficiency mode issue 2861
💡 Result:
The issue referenced as #2861 in the Wails repository [1] relates to scenarios where WebView2 applications may fail to display or become unresponsive due to Windows Efficiency Mode. In Microsoft WebView2, Efficiency Mode is a resource-management feature that can throttle or suspend processes—typically renderer processes associated with the WebView2 control—when the system determines the control is inactive or not visible [2][3]. The PutIsVisible method (available via the ICoreWebView2Controller interface) [4][5][6] is the primary API used to manage the visibility state of a WebView2 control. The official guidance from Microsoft is to keep the IsVisible property set to true to indicate that the control is active and to avoid unnecessary throttling by Efficiency Mode [2][3]. Key technical points regarding this issue include: - Behavior: When IsVisible is set to false, WebView2 may purge memory or throttle activity [4]. While this is a documented performance optimization (e.g., when a window is minimized) [4], it can interfere with applications if the system incorrectly flags the WebView2 instance as inactive, leading to scenarios where the window fails to render or loses communication with the host application runtime [1]. - Wails Implementation: The Wails project has implemented workarounds for this behavior in its window management logic [7]. These workarounds include ensuring the window is shown and, if navigation is delayed, triggering a forced call to the show logic to prevent the WebView2 from remaining permanently invisible or suspended due to system-level Efficiency Mode management [7]. - Documentation: Microsoft notes that developers should handle WM_SIZE messages to toggle IsVisible (e.g., FALSE when minimized, TRUE when restored) to balance resource usage and performance correctly [4]. However, relying on this to avoid Efficiency Mode issues remains a common point of discussion, as developers sometimes require the control to stay active regardless of apparent UI visibility [3].
Citations:
- 1: App window is not showing #2861
- 2: Disable Efficiency Mode MicrosoftEdge/WebView2Feedback#3238
- 3: Disable Efficiency Mode MicrosoftEdge/WebView2Feedback#4021
- 4: https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2controller?view=webview2-1.0.3912.50
- 5: https://docs.rs/webview2-sys/latest/webview2_sys/struct.ICoreWebView2ControllerVTable.html
- 6: https://pkg.go.dev/github.com/Aivaki/wails-garble/v2/internal/frontend/desktop/windows/go-webview2/pkg/edge
- 7: https://github.com/wailsapp/wails/blob/3ec88c12/v3/pkg/application/webview_window_windows.go
Scope the Windows option to the hidden-and-never-shown case.
The design says the Windows preference keeps the controller visible while the window is hidden, but the implementation leaves every later hide/minimize/restore transition on the existing Show()/Hide() paths. Keep the same contract in that implementation, or change the option wording to mean only a hidden window that has never been shown.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@v3/wep/proposals/keep-running-when-hidden/proposal.md` around lines 26 - 27,
Align the Windows preference wording with its implementation: either update the
hidden-window behavior to keep the WebView2 controller visible across later
hide, minimize, and restore transitions, or explicitly scope the option to
windows that are hidden and have never been shown. Update the Windows option
description in the proposal so it matches the chosen contract.
Source: MCP tools
Add an opt-in per-window preference that stops the platform WebView from throttling JavaScript while the window is hidden
FYI, here's my reference implementation:
https://github.com/juggler-ai/wails/tree/feat/mac-dock-bounce-on-flash