Skip to content

Commit

Permalink
feat(cache): cache resources (project pages, css, font, js, image) us…
Browse files Browse the repository at this point in the history
…ing service worker (#239)
  • Loading branch information
hudy9x authored Jul 18, 2024
1 parent 904063c commit 7a5c309
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 1 deletion.
2 changes: 1 addition & 1 deletion packages/ui-app/app/[orgName]/meeting/MeetingRoomList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export default function MeetingRoomList() {
// only clear fixed loading as the page unmount
useEffect(() => {
return () => {
setFixLoading(false)
// setFixLoading(false)
}
})

Expand Down
13 changes: 13 additions & 0 deletions packages/ui-app/app/_features/ServiceWorker/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
'use client'
import { useEffect } from "react"

export default function RegisterServiceWorker() {
useEffect(() => {
if ('serviceWorker' in window.navigator) {
window.navigator.serviceWorker
.register('/sw-cache-resources.js')
.then(registration => console.log('Scope is:', registration, registration.scope))
}
})
return <></>
}
2 changes: 2 additions & 0 deletions packages/ui-app/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import RootLayoutComp from '../layouts/RootLayout'
import { GoalieProvider } from '@goalie/nextjs'

import dynamic from 'next/dynamic'
import RegisterServiceWorker from './_features/ServiceWorker'
const inter = Inter({ subsets: ['latin'] })

const PushNotification = dynamic(
Expand All @@ -33,6 +34,7 @@ export default function RootLayout({
<body className={inter.className}>
<RootLayoutComp>{children}</RootLayoutComp>
<PushNotification />
<RegisterServiceWorker />
</body>
</html>
</GoalieProvider>
Expand Down
169 changes: 169 additions & 0 deletions packages/ui-app/public/sw-cache-resources.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
// everytime you deploy new frontend version, please update the cache version
const cacheVersion = 'v0.1'

const cacheClone = async (e) => {
const res = await fetch(e.request);
const resClone = res.clone();

const cache = await caches.open(cacheVersion);
await cache.put(e.request, resClone);
return res;
};

const deleteOldCaches = async () => {
const keys = await caches.keys()
keys.map(async k => {
if (k === cacheVersion) return
console.log('delete key', k)
await caches.delete(k)
})
}

const cacheResource = async (cacheName, event) => {
const cache = await caches.open(cacheName);
const cachedResponse = await cache.match(event.request)

if (cachedResponse) {
return cachedResponse
}

const res = await fetch(event.request);
const resClone = res.clone();

await cache.put(event.request, resClone);
return res;
}

const cacheFirstThenFetch = async (cacheName, event) => {
const cache = await caches.open(cacheName);
const cachedResponse = await cache.match(event.request)

if (cachedResponse) {
event.waitUntil( // Schedule a background update
fetch(event.request).then((networkResponse) => {
cache.put(event.request, networkResponse.clone());
})
);

return cachedResponse
}

const res = await fetch(event.request);
const resClone = res.clone();

await cache.put(event.request, resClone);
return res;
}


const isEmojiResources = (url) => {
return url.includes('cdn.jsdelivr.net/npm/emoji-datasource-twitter/img')
}

const cacheEmojiResources = async (event) => {
cacheResource(cacheVersion, event)
}

const isNextjsStaticResource = (url) => {
return url.includes('_next/static');

}

const cachedNextStaticResources = async (event) => {
cacheResource(cacheVersion, event)
}

const isOtherNextResource = (url) => {
return url.includes('__nextjs_original-stack-frame');
}

const cacheOtherNextResource = async (event) => {
cacheResource(cacheVersion, event)
}

const cacheProjectPage = async (event) => {
cacheFirstThenFetch(cacheVersion, event)
}

const isApiRequest = (url) => {
return url.includes('/api/');
}

const isProjectPage = (url) => {
const urlObj = new URL(url)

if (!urlObj.pathname) return

const path = urlObj.pathname.split('/').filter(Boolean)

return path.length === 3 && path[1] === 'project'

}

const isGmailAvatar = (url) => {
return url.includes('lh3.googleusercontent.com');
}

const cacheGmailAvatar = async (event) => {
cacheFirstThenFetch(cacheVersion, event)
}

const fetchEvent = () => {

// delete old caches
deleteOldCaches()

self.addEventListener('fetch', (e) => {
const url = e.request.url

// cache fixed images like emoji picker
if (isEmojiResources(url)) {
cacheEmojiResources(e)
return
}

if (isNextjsStaticResource(url)) {
cachedNextStaticResources(e)
return
}

if (isOtherNextResource(url)) {
cacheOtherNextResource(e)
// e.respondWith(fetch(e.request))
return
}

if (isProjectPage(url)) {
cacheProjectPage(e)
return
}

if (isGmailAvatar(url)) {
cacheGmailAvatar(e)
}

if (isApiRequest(url)) {
// console.log('request url', url)
// e.respondWith(fetch(e.request))
return
}

});
};

fetchEvent();

const installEvent = () => {
self.addEventListener('install', () => {
console.log('service worker installed');
});
};
installEvent();

const activateEvent = () => {
self.addEventListener('activate', () => {
console.log('service worker activated');
});
};
activateEvent();

0 comments on commit 7a5c309

Please sign in to comment.