Skip to content

fix: add Safari/iOS fallback for controllerchange not firing in prompt mode#937

Open
lucas-spin wants to merge 1 commit into
vite-pwa:mainfrom
lucas-spin:fix/safari-ios-controlling-fallback
Open

fix: add Safari/iOS fallback for controllerchange not firing in prompt mode#937
lucas-spin wants to merge 1 commit into
vite-pwa:mainfrom
lucas-spin:fix/safari-ios-controlling-fallback

Conversation

@lucas-spin

Copy link
Copy Markdown

Closes #524

Problem

In prompt mode (registerType: 'prompt'), after the user accepts the update and updateSW(true) is called:

  1. wb.messageSkipWaiting() sends SKIP_WAITING to the waiting service worker
  2. The SW calls self.skipWaiting() and activates
  3. The plugin listens for Workbox's 'controlling' event (which wraps navigator.serviceWorker's controllerchange) to trigger the page reload

On Safari/iOS (WebKit), step 3 fails silently — controllerchange does not fire reliably, especially in standalone/home-screen mode. This leaves users stuck after clicking the refresh button, with no error and no reload.

This is a well-documented WebKit limitation that has affected users since 2023 (see #524, which has been open with no fix).

Solution

Added a timeout-based fallback in updateServiceWorker():

let controllingReceived = false

// In the controlling listener:
wb.addEventListener('controlling', (event) => {
  if (event.isUpdate) {
    controllingReceived = true
    // ... reload
  }
})

// In updateServiceWorker:
sendSkipWaitingMessage?.()
if (reloadPage) {
  setTimeout(() => {
    if (!controllingReceived) {
      window.location.reload()
    }
  }, 2000)
}

How it works:

  • On Chrome/Firefox: controlling fires within ~50ms → sets controllingReceived = true → timeout is a no-op
  • On Safari/iOS: controlling never fires → after 2s the fallback triggers the reload

Additional fix: The _reloadPage parameter was previously unused (underscore-prefixed, never referenced). It's now wired up to gate the fallback — callers can pass updateSW(false) to skip the auto-reload if they handle it manually via onNeedReload.

Impact

  • No behavioral change on browsers where controllerchange fires correctly
  • Fixes the stuck refresh on Safari, iOS Safari, iOS standalone/home-screen PWAs, and WKWebView-based browsers
  • Minimal code change (~10 lines added)

References

@netlify

netlify Bot commented May 28, 2026

Copy link
Copy Markdown

Deploy Preview for vite-plugin-pwa-legacy ready!

Name Link
🔨 Latest commit b824946
🔍 Latest deploy log https://app.netlify.com/projects/vite-plugin-pwa-legacy/deploys/6a18740820931d0008218e2e
😎 Deploy Preview https://deploy-preview-937--vite-plugin-pwa-legacy.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

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.

Added to the home screen, automatic updates are not functioning.

1 participant