@@ -27,52 +27,59 @@ export function useReloadWhenSwChange() {
27
27
}
28
28
29
29
navigator . serviceWorker . register ( '/sw.js' ) . then ( ( registration ) => {
30
- // Track updates to the Service Worker.
31
30
if ( ! navigator . serviceWorker . controller ) {
32
- // The window client isn't currently controlled so it's a new service
33
- // worker that will activate immediately
34
31
return ;
35
32
}
36
33
registration . update ( ) ;
37
34
38
- handleNewServiceWorker ( registration , ( ) => {
39
- if ( ! registration . waiting ) {
40
- // Just to ensure registration.waiting is available before
41
- // calling postMessage()
42
- return ;
35
+ // Handle both page refresh/close and SPA navigation
36
+ const skipWaitingOnNavigation = ( ) => {
37
+ if ( registration . waiting ) {
38
+ logger . debug ( 'Activating new service worker on navigation' ) ;
39
+ registration . waiting . postMessage ( 'skipWaiting' ) ;
43
40
}
41
+ } ;
44
42
45
- registration . waiting . postMessage ( 'skipWaiting' ) ;
46
- } ) ;
47
- } ) ;
48
- } , [ ] ) ;
49
- }
43
+ // Listen for regular page unload
44
+ window . addEventListener ( 'beforeunload' , skipWaitingOnNavigation ) ;
50
45
51
- function handleNewServiceWorker (
52
- registration : ServiceWorkerRegistration ,
53
- callback : ( ) => void ,
54
- ) {
55
- if ( registration . waiting ) {
56
- // SW is waiting to activate. Can occur if multiple clients open and
57
- // one of the clients is refreshed.
58
- return callback ( ) ;
59
- }
46
+ // Listen for SPA navigation
47
+ window . addEventListener ( 'popstate' , skipWaitingOnNavigation ) ;
48
+ const originalPushState = history . pushState . bind ( history ) ;
49
+ const originalReplaceState = history . replaceState . bind ( history ) ;
60
50
61
- function listenInstalledStateChange ( ) {
62
- registration . installing ?. addEventListener ( 'statechange' , ( event : Event ) => {
63
- // @ts -ignore
64
- if ( event . target ?. state === 'installed' ) {
65
- // A new service worker is available, inform the user
66
- callback ( ) ;
67
- }
68
- } ) ;
69
- }
51
+ history . pushState = ( ... args ) => {
52
+ originalPushState ( ... args ) ;
53
+ skipWaitingOnNavigation ( ) ;
54
+ } ;
55
+
56
+ history . replaceState = ( ... args ) => {
57
+ originalReplaceState ( ... args ) ;
58
+ skipWaitingOnNavigation ( ) ;
59
+ } ;
70
60
71
- if ( registration . installing ) {
72
- return listenInstalledStateChange ( ) ;
73
- }
61
+ registration . addEventListener ( 'updatefound' , ( ) => {
62
+ registration . installing ?. addEventListener (
63
+ 'statechange' ,
64
+ ( event : Event ) => {
65
+ // @ts -ignore
66
+ if ( event . target ?. state === 'installed' && registration . waiting ) {
67
+ // Will activate on next navigation
68
+ logger . debug (
69
+ 'New service worker installed, waiting for navigation' ,
70
+ ) ;
71
+ }
72
+ } ,
73
+ ) ;
74
+ } ) ;
74
75
75
- // We are currently controlled so a new SW may be found...
76
- // Add a listener in case a new SW is found,
77
- registration . addEventListener ( 'updatefound' , listenInstalledStateChange ) ;
76
+ // Cleanup
77
+ return ( ) => {
78
+ window . removeEventListener ( 'beforeunload' , skipWaitingOnNavigation ) ;
79
+ window . removeEventListener ( 'popstate' , skipWaitingOnNavigation ) ;
80
+ history . pushState = originalPushState ;
81
+ history . replaceState = originalReplaceState ;
82
+ } ;
83
+ } ) ;
84
+ } , [ ] ) ;
78
85
}
0 commit comments