Skip to content

Disconnect HMR WebSocket on pagehide for BFCache compatibility #22361

@kyraac

Description

@kyraac

Description

BFCache is a browser performance feature that enables instant back/forward navigation. It would be useful to have BFCache work in Vite dev environments so that navigation performance can be tested and developed against accurately. Currently this is not possible: browsers disqualify pages with open WebSocket connections from BFCache, and Vite's @vite/client keeps an HMR WebSocket open for the lifetime of the page.

Will open a PR for this

Suggested solution

In packages/vite/src/client/client.ts, add pagehide/pageshow listeners alongside the existing beforeunload block:

if (typeof window !== 'undefined') {
  window.addEventListener?.('pagehide', () => {
    transport.disconnect?.()
  })
  window.addEventListener?.('pageshow', async (event: PageTransitionEvent) => {
    if (event.persisted) {
      await transport.connect!(createHMRHandler(handleMessage))
    }
  })
}

unload and beforeunload are intentionally avoided as registering listeners for either also disqualifies pages from BFCache.

Alternative

  • Export transport from client.ts so downstream integrations can manage the lifecycle themselves. This adds API surface and places the burden on each integrator rather than fixing it universally.
  • Downstream integrations could wrap window.WebSocket before @vite/client loads to intercept and hold a reference to the socket. This relies on script ordering and internal implementation details.

Additional context

No response

Validations

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions