Skip to content

Fix reconnect on visibilitychange never running (window.hiddenProperty is always truthy) - #499

Open
TowyTowy wants to merge 1 commit into
schlagmichdoch:masterfrom
TowyTowy:fix/498-visibilitychange-reconnect
Open

Fix reconnect on visibilitychange never running (window.hiddenProperty is always truthy)#499
TowyTowy wants to merge 1 commit into
schlagmichdoch:masterfrom
TowyTowy:fix/498-visibilitychange-reconnect

Conversation

@TowyTowy

Copy link
Copy Markdown

What & why

Fixes #498.

ServerConnection._onVisibilityChange() never reconnects the signaling socket when the page returns to the foreground:

_onVisibilityChange() {
    if (window.hiddenProperty) return;
    this._connect();
}

window.hiddenProperty (set in util.js) is the name of the visibility property — the string 'hidden' (or a vendor-prefixed variant), not the page's visibility state. A non-empty string is always truthy, so the guard always returns early and this._connect() is dead code: the client never re-establishes the WebSocket on visibilitychange.

git log -L shows this was introduced in 2a837eb ("add 'visbilitychange' event support for older browsers"), which changed if (document.hidden) return; to if (window.hiddenProperty) return; and dropped the document[...] indexing.

Fix

Index document with the property name, restoring the original pre-polyfill behaviour while keeping vendor-prefix support:

if (document[window.hiddenProperty]) return;

The guard now returns early only while the page is actually hidden and lets _connect() run when it becomes visible — the intended recover-on-return path. This most visibly affects standalone PWAs (e.g. iPadOS home-screen web apps) whose socket is severed while backgrounded, which is the symptom reported in #498.

Verification

  • node --check public/scripts/network.js passes.
  • Standalone Node harness replicating the util.js polyfill + both guards: hidden page → _connect() correctly skipped (before and after); visible page → skipped before the fix (the bug), called after (correct); vendor-prefixed (webkitHidden) visible page → correctly calls _connect() after the fix.
  • The hiddenProperty === null path (no visibility API) is unaffected: visibilityChangeEvent is then also null, so the listener never fires.

Out of scope (possible follow-up)

Issue #498 also notes that on iPadOS the resumed socket can be a "zombie" whose readyState still reads OPEN, so _connect()'s _isConnected() early-return may skip reconnecting even after this fix, since the client has no self-initiated ping timeout. Robustly handling that changes cross-platform behaviour and can't be verified without the physical device, so I've left it out of this minimal, deterministic fix.


Disclosure: this one-line fix was prepared with AI assistance (Claude); the root cause, the change, and the verification above were reviewed before submission.

`_onVisibilityChange()` guarded the reconnect with
`if (window.hiddenProperty) return;`. `window.hiddenProperty` is the
*name* of the visibility property (the string `'hidden'`, or a
vendor-prefixed variant), set by the polyfill in util.js. A non-empty
string is always truthy, so the guard always returns early and
`this._connect()` is dead code — the page never reconnects when it
becomes visible again.

Read the actual visibility state instead by indexing into `document`
with the property name, restoring the pre-polyfill behaviour
(`if (document.hidden) return;`) while keeping vendor-prefix support:

    if (document[window.hiddenProperty]) return;

Now the guard returns early only while the page is hidden and lets
`_connect()` run when it becomes visible, which is the intended
recover-on-return path (notably for standalone PWAs whose socket was
severed while backgrounded).

Fixes schlagmichdoch#498

Co-Authored-By: Claude Fable 5 <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.

[Bug] Stuck offline after app switch on iPadOS PWA — reconnect on visibilitychange is dead code (window.hiddenProperty is always truthy)

1 participant