Skip to content

fix: close WebSocket on pagehide to support bfcache#162

Open
FeironoX5 wants to merge 2 commits intomasterfrom
fix/websocket-bfcache
Open

fix: close WebSocket on pagehide to support bfcache#162
FeironoX5 wants to merge 2 commits intomasterfrom
fix/websocket-bfcache

Conversation

@FeironoX5
Copy link

Original problem

Lighthouse was giving an exception "Pages with WebSocket cannot enter back/forward cache (bfcache)" because we were not closing socket on pagehide event.

PR Description

Solution from MDN reference was implemented. When reproducing notice that vite dev also opens a socket, so, instead use npx vite build with npx serve and import changing in index.html. pageshow event is ignored, because socket connection will be restored when send method will be called.

изображение

@FeironoX5 FeironoX5 requested a review from neSpecc February 13, 2026 14:59
this.reconnectionAttempts = reconnectionAttempts;

this.pageHideHandler = () => {
log('Page entering bfcache, closing WebSocket', 'info');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think users will be happy to see this log in their application. Let's remove it after testing.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the JavaScript Socket transport to close its WebSocket connection on pagehide, enabling the page to enter the browser back/forward cache (bfcache) and addressing Lighthouse warnings.

Changes:

  • Adds a pagehide event handler that closes the WebSocket.
  • Registers/unregisters the pagehide listener when the socket opens/closes.
  • Introduces an internal close() helper to null out the socket after closing.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +142 to +144
private setupListeners(): void {
window.addEventListener('pagehide', this.pageHideHandler, { capture: true });
}
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new bfcache behavior (listening to pagehide and closing the WebSocket) isn’t covered by tests. Since this package already uses Vitest + jsdom, it should be possible to add a unit test that mocks WebSocket, dispatches a pagehide event (with persisted: true if you adopt that check), and asserts that close() is called and that a later send() recreates the connection.

Copilot uses AI. Check for mistakes.
Comment on lines +85 to +88
this.pageHideHandler = () => {
log('Page entering bfcache, closing WebSocket', 'info');
this.close();
};
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pageHideHandler always logs "Page entering bfcache" and closes the socket, but it doesn’t receive the pagehide event so it can’t check event.persisted. This makes the log message inaccurate and deviates from the MDN pattern (close only when the page is being persisted to bfcache). Consider typing the handler as (event: PageTransitionEvent) => void, checking event.persisted, and updating the log message accordingly (or only logging when persisted is true).

Copilot uses AI. Check for mistakes.
* Create new WebSocket connection and setup event listeners
* Remove window event listeners
*/
public destroyListeners(): void {
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

destroyListeners() is declared public, but it appears to be an internal helper (only used inside this class). Exposing it expands the public API surface of Socket without being part of the Transport interface; consider making it private (or introducing a single public destroy() method that both removes listeners and closes the socket if external cleanup is intended).

Suggested change
public destroyListeners(): void {
private destroyListeners(): void {

Copilot uses AI. Check for mistakes.
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.

3 participants