Skip to content

Commit c602ccf

Browse files
authored
Merge pull request #1631 from devtron-labs/service-worker-fix
fix: Service worker issue
2 parents f682f9b + 19b94a9 commit c602ccf

File tree

4 files changed

+96
-17
lines changed

4 files changed

+96
-17
lines changed

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,9 @@
121121
"workbox-window": "7.0.0",
122122
"workbox-core": "^7.0.0",
123123
"workbox-precaching": "^7.0.0",
124-
"workbox-routing": "^7.0.0"
124+
"workbox-routing": "^7.0.0",
125+
"workbox-navigation-preload": "7.0.0",
126+
"workbox-strategies": "7.0.0"
125127
},
126128
"jest": {
127129
"collectCoverageFrom": [

src/App.tsx

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ export default function App() {
4747
const updateToastRef = useRef(null)
4848
const [errorPage, setErrorPage] = useState<boolean>(false)
4949
const isOnline = useOnline()
50+
const refreshing = useRef(false)
51+
const [bgUpdated, setBGUpdated] = useState(false)
5052
const [validating, setValidating] = useState(true)
5153
const [approvalToken, setApprovalToken] = useState<string>('')
5254
const [approvalType, setApprovalType] = useState<APPROVAL_MODAL_TYPE>(APPROVAL_MODAL_TYPE.CONFIG)
@@ -129,7 +131,22 @@ export default function App() {
129131
}
130132
}
131133

134+
function handleControllerChange() {
135+
if (refreshing.current) {
136+
return
137+
}
138+
if (document.visibilityState === 'visible') {
139+
window.location.reload()
140+
refreshing.current = true
141+
} else {
142+
setBGUpdated(true)
143+
}
144+
}
145+
132146
useEffect(() => {
147+
if (navigator.serviceWorker) {
148+
navigator.serviceWorker.addEventListener('controllerchange', handleControllerChange)
149+
}
133150
// If not K8S_CLIENT then validateToken otherwise directly redirect
134151
if (!window._env_.K8S_CLIENT) {
135152
// By Passing validations for direct email approval notifications
@@ -142,6 +159,9 @@ export default function App() {
142159
setValidating(false)
143160
defaultRedirection()
144161
}
162+
return () => {
163+
navigator.serviceWorker.removeEventListener('controllerchange', handleControllerChange)
164+
}
145165
}, [])
146166

147167
const {
@@ -150,9 +170,20 @@ export default function App() {
150170
} = useRegisterSW({
151171
onRegisteredSW(swUrl, r) {
152172
console.log(`Service Worker at: ${swUrl}`)
153-
if (r) {
154-
r.update()
155-
}
173+
r &&
174+
setInterval(async () => {
175+
if (!(!r.installing && navigator)) return
176+
if ('connection' in navigator && !navigator.onLine) return
177+
const resp = await fetch(swUrl, {
178+
cache: 'no-store',
179+
headers: {
180+
cache: 'no-store',
181+
'cache-control': 'no-cache',
182+
},
183+
})
184+
185+
if (resp?.status === 200) await r.update()
186+
}, 1000 * 60)
156187
},
157188
onRegisterError(error) {
158189
console.log('SW registration error', error)
@@ -169,10 +200,11 @@ export default function App() {
169200
if (window.isSecureContext && navigator.serviceWorker) {
170201
// check for sw updates on page change
171202
navigator.serviceWorker.getRegistrations().then((regs) => regs.forEach((reg) => reg.update()))
172-
if (!needRefresh) {
173-
return
203+
if (needRefresh) {
204+
update()
205+
} else if (toast.isActive(updateToastRef.current)) {
206+
toast.dismiss(updateToastRef.current)
174207
}
175-
update()
176208
}
177209
}, [location])
178210

@@ -200,6 +232,24 @@ export default function App() {
200232
}
201233
}, [needRefresh])
202234

235+
useEffect(() => {
236+
if (!bgUpdated) {
237+
return
238+
}
239+
const bgUpdatedToastBody = (
240+
<UpdateToast
241+
onClick={() => window.location.reload()}
242+
text="This page has been updated. Please save any unsaved changes and refresh."
243+
buttonText="Reload"
244+
/>
245+
)
246+
if (toast.isActive(updateToastRef.current)) {
247+
toast.update(updateToastRef.current, { render: bgUpdatedToastBody })
248+
} else {
249+
updateToastRef.current = toast.info(bgUpdatedToastBody, { autoClose: false, closeButton: false })
250+
}
251+
}, [bgUpdated])
252+
203253
return (
204254
<Suspense fallback={null}>
205255
{validating ? (

src/service-worker.ts

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
import { cleanupOutdatedCaches, createHandlerBoundToURL, precacheAndRoute } from 'workbox-precaching'
2-
import { NavigationRoute, registerRoute } from 'workbox-routing'
1+
import { precacheAndRoute, cleanupOutdatedCaches } from 'workbox-precaching'
2+
import { NavigationRoute, registerRoute, Route } from 'workbox-routing'
3+
import * as navigationPreload from 'workbox-navigation-preload'
4+
import { NetworkFirst, StaleWhileRevalidate } from 'workbox-strategies'
5+
import { clientsClaim } from 'workbox-core'
36

47
declare let self: ServiceWorkerGlobalScope
58

@@ -10,11 +13,40 @@ self.addEventListener('message', (event) => {
1013
}
1114
})
1215

13-
// self.__WB_MANIFEST is default injection point
16+
clientsClaim()
17+
18+
// Precache the manifest
1419
precacheAndRoute(self.__WB_MANIFEST)
1520

1621
// clean old assets
1722
cleanupOutdatedCaches()
1823

19-
// to allow work offline
20-
registerRoute(new NavigationRoute(createHandlerBoundToURL('index.html')))
24+
// Enable navigation preload
25+
navigationPreload.enable()
26+
27+
// Create a new navigation route that uses the Network-first, falling back to
28+
// cache strategy for navigation requests with its own cache. This route will be
29+
// handled by navigation preload. The NetworkOnly strategy will work as well.
30+
const navigationRoute = new NavigationRoute(
31+
new NetworkFirst({
32+
cacheName: 'navigations',
33+
}),
34+
)
35+
36+
// Register the navigation route
37+
registerRoute(navigationRoute)
38+
39+
// Create a route for image, script, or style requests that use a
40+
// stale-while-revalidate strategy. This route will be unaffected
41+
// by navigation preload.
42+
const staticAssetsRoute = new Route(
43+
({ request }) => {
44+
return ['image', 'script', 'style'].includes(request.destination)
45+
},
46+
new StaleWhileRevalidate({
47+
cacheName: 'static-assets',
48+
}),
49+
)
50+
51+
// Register the route handling static assets
52+
registerRoute(staticAssetsRoute)

vite.config.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,6 @@ export default defineConfig(({ mode }) => {
9595
baseConfig['define'] = {
9696
global: 'globalThis',
9797
}
98-
// } else {
99-
// baseConfig['define'] = {
100-
// __BASE_URL__: '/dashboard/',
101-
// __ORCHESTRATOR_ROOT__: '/orchestrator',
102-
// }
10398
}
10499

105100
return baseConfig

0 commit comments

Comments
 (0)