Skip to content

Commit

Permalink
Add reload on update
Browse files Browse the repository at this point in the history
  • Loading branch information
theninthsky committed Dec 8, 2022
1 parent d169123 commit 9a26841
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 6 deletions.
50 changes: 50 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ This project is a case study of CSR, it aims to explore the potential of client-
- [The Biggest Drawback of SSR](#the-biggest-drawback-of-ssr)
- [The SWR Approach](#the-swr-approach)
- [Implementing SWR](#implementing-swr)
- [Reloading On Update](#reloading-on-update)
- [Revalidating Active Apps](#revalidating-active-apps)
- [Revalidating Installed Apps](#revalidating-installed-apps)
- [Summary](#summary)
Expand Down Expand Up @@ -1021,6 +1022,55 @@ These metrics are coming from a 5-year-old `Intel i3-8130U` laptop when the brow
Now that we've seen that nothing can match SWR in terms of performance, our new goal is to try to keep users' apps as much up-to-date as possible, without compromising on the SWR allowed time period.
### Reloading On Update
When a user opens our app and there's and update, the browser will replace the old cached files with the new ones. The user then will see the update only when they reload the page.
<br>
If we wanted to update to be visible right away, we could manually reload the app.
<br>
However, reloading the app while the user is viewing it is a very bad idea. Instead, we can reload the app while it is _hidden_:

_[service-worker.js](public/service-worker.js)_

```diff
.
.
.
self.addEventListener('install', async event => {
event.waitUntil(preCache())
self.skipWaiting()
+ const [windowClient] = await clients.matchAll({ includeUncontrolled: true, type: 'window' })
+ windowClient.postMessage({ type: 'update-available' })
})
.
.
.
```

_[index.jsx](src/index.jsx)_

```js
import pagesManifest from 'pages-manifest.json'
navigator.serviceWorker.addEventListener('message', ({ data }) => {
if (data.type === 'update-available') {
window.addEventListener('visibilitychange', () => {
let { pathname } = window.location
if (pathname !== '/') pathname = pathname.replace(/\/$/, '')
const allowReload = pagesManifest.find(({ path, allowReload }) => allowReload && isStructureEqual(pathname, path))
if (allowReload && document.visibilityState === 'hidden') window.location.reload()
})
}
})
```

_Note that we define the pages in which the reload is allowed, that's in order to prevent reloading in critical times such as filling out forms._
### Revalidating Active Apps
Some users leave the app open for extended periods of time, so another thing we can do is to revalidate the app while it is running:
Expand Down
6 changes: 5 additions & 1 deletion public/service-worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,13 @@ const staleWhileRevalidate = async request => {
return cachedResponsePromise || networkResponsePromise
}

self.addEventListener('install', event => {
self.addEventListener('install', async event => {
event.waitUntil(preCache())
self.skipWaiting()

const [windowClient] = await clients.matchAll({ includeUncontrolled: true, type: 'window' })

windowClient.postMessage({ type: 'update-available' })
})

self.addEventListener('fetch', event => {
Expand Down
15 changes: 15 additions & 0 deletions src/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { StyledEngineProvider } from '@mui/material/styles'

import 'service-worker-registration'
import 'styles'
import pagesManifest from 'pages-manifest.json'
import App from './App'

createRoot(document.getElementById('root')).render(
Expand All @@ -19,4 +20,18 @@ createRoot(document.getElementById('root')).render(
</BrowserRouter>
)

navigator.serviceWorker.addEventListener('message', ({ data }) => {
if (data.type === 'update-available') {
window.addEventListener('visibilitychange', () => {
let { pathname } = window.location

if (pathname !== '/') pathname = pathname.replace(/\/$/, '')

const allowReload = pagesManifest.find(({ path, allowReload }) => allowReload && isStructureEqual(pathname, path))

if (allowReload && document.visibilityState === 'hidden') window.location.reload()
})
}
})

new BroadcastChannel('main').onmessage = ({ data }) => localStorage.setItem('syncTime', data.syncTime)
15 changes: 10 additions & 5 deletions src/pages-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"chunk": "home",
"path": "/",
"title": "Home",
"description": "This page demonstrates a large amount of components that are rendered on the screen."
"description": "This page demonstrates a large amount of components that are rendered on the screen.",
"allowReload": true
},
{
"chunk": "lorem-ipsum",
Expand All @@ -13,7 +14,8 @@
"data": {
"url": "/json/lorem-ipsum.json",
"menuPreload": true
}
},
"allowReload": true
},
{
"chunk": "pokemon",
Expand All @@ -26,7 +28,8 @@
"crossorigin": "anonymous",
"menuPreload": true
}
]
],
"allowReload": true
},
{
"chunk": "pokemon-info",
Expand All @@ -38,7 +41,8 @@
"crossorigin": "anonymous",
"preconnectURL": "https://raw.githubusercontent.com"
},
"menuItem": false
"menuItem": false,
"allowReload": true
},
{
"chunk": "core-web-vitals",
Expand All @@ -50,6 +54,7 @@
"chunk": "periodic-sync",
"path": "/periodic-sync",
"title": "Periodic Sync",
"description": "This page specifies the time of the last periodic background sync."
"description": "This page specifies the time of the last periodic background sync.",
"allowReload": true
}
]

0 comments on commit 9a26841

Please sign in to comment.