diff --git a/packages/client/index.html b/packages/client/index.html index 7d4a47b..34ac846 100644 --- a/packages/client/index.html +++ b/packages/client/index.html @@ -3,6 +3,7 @@ + diff --git a/packages/client/public/manifest.json b/packages/client/public/manifest.json new file mode 100644 index 0000000..7f000d4 --- /dev/null +++ b/packages/client/public/manifest.json @@ -0,0 +1,15 @@ +{ + "short_name": "FTanks", + "name": "Falcon Tanks", + "icons": [ + { + "src": "./public/favicon.png", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/packages/client/public/serviceWorker.js b/packages/client/public/serviceWorker.js new file mode 100644 index 0000000..7a7c762 --- /dev/null +++ b/packages/client/public/serviceWorker.js @@ -0,0 +1,55 @@ +const CACHE_NAME = 'cache-data-v1' +const urlsToCache = [ + '/' +] + +const networkFirst = async (request) => { + const cache = await caches.open(CACHE_NAME) + try { + const response = await fetch(request) + const cachePutCondition = response && response.status === 200 && response.type === 'basic' + if (cachePutCondition) { + await cache.put(request, response.clone()) + } + return response + } catch (error) { + console.error('Fetch failed; returning cached page instead.', error) + const cachedResponse = await cache.match(request) + if (cachedResponse) { + return cachedResponse + } + return new Response('Network error happened', { + status: 503, + headers: { 'Content-Type': 'text/plain' }, + }) + } +} + +self.addEventListener('install', (event) => { + event.waitUntil( + caches + .open(CACHE_NAME) + .then((cache) => { + return cache.addAll(urlsToCache) + }) + .then(() => self.skipWaiting()) + .catch((err) => { + console.error('Cache installation failed:', err) + }) + ) +}) + +self.addEventListener('fetch', (event) => { + const { request } = event + const { url, method } = request + + if (method !== 'GET') { + return + } + + if (!url.startsWith('http')) { + return + } + + event.respondWith(networkFirst(request)) +}) diff --git a/packages/client/src/main.tsx b/packages/client/src/main.tsx index d701aa8..68b12bf 100644 --- a/packages/client/src/main.tsx +++ b/packages/client/src/main.tsx @@ -6,6 +6,7 @@ import { ToastContainer } from 'react-toastify' import 'react-toastify/dist/ReactToastify.css' import App from './app/App' import '@/scss/styles.scss' +import { registerServiceWorker } from './registerServiceWorker' ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( @@ -15,3 +16,5 @@ ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( ) + +registerServiceWorker() diff --git a/packages/client/src/registerServiceWorker.ts b/packages/client/src/registerServiceWorker.ts new file mode 100644 index 0000000..a9fe514 --- /dev/null +++ b/packages/client/src/registerServiceWorker.ts @@ -0,0 +1,24 @@ +export const registerServiceWorker = () => { + if ('serviceWorker' in navigator) { + window.addEventListener('load', () => { + navigator.serviceWorker + .register('./serviceWorker.js') + .then( + registration => { + console.log( + 'ServiceWorker registration successful with scope: ', + registration.scope + ) + }, + err => { + throw new Error(`ServiceWorker registration failed: ${err}`) + } + ) + .catch(err => { + throw new Error(err) + }) + }) + } else { + throw new Error('service worker is not supported') + } +} diff --git a/packages/client/vite.config.ts b/packages/client/vite.config.ts index 3ac4356..c20ba74 100644 --- a/packages/client/vite.config.ts +++ b/packages/client/vite.config.ts @@ -23,4 +23,13 @@ export default defineConfig({ }, plugins: [react()], envDir: '../../', + build: { + outDir: 'dist', + rollupOptions: { + input: { + main: path.resolve(__dirname, 'index.html'), + serviceWorker: path.resolve(__dirname, 'public/serviceWorker.js'), + }, + }, + }, })