mirror of
https://github.com/jcreek/LivingDexTracker.git
synced 2026-07-13 02:53:45 +00:00
chore(*): Add workbox service worker
This commit is contained in:
Vendored
+19
-7
@@ -1,13 +1,25 @@
|
||||
import 'vite-plugin-pwa/svelte';
|
||||
import 'vite-plugin-pwa/info';
|
||||
import 'vite-plugin-pwa/pwa-assets';
|
||||
|
||||
// See https://kit.svelte.dev/docs/types#app
|
||||
// for information about these interfaces
|
||||
// and what to do when importing types
|
||||
declare global {
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
// interface Locals {}
|
||||
// interface PageData {}
|
||||
// interface PageState {}
|
||||
// interface Platform {}
|
||||
}
|
||||
const __DATE__: string;
|
||||
const __RELOAD_SW__: boolean;
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
interface Locals {
|
||||
userid: string;
|
||||
buildDate: string;
|
||||
periodicUpdates: boolean;
|
||||
}
|
||||
|
||||
// interface PageData {}
|
||||
// interface PageState {}
|
||||
// interface Platform {}
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
|
||||
@@ -4,20 +4,6 @@
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="manifest" href="/site.webmanifest" />
|
||||
<meta name="theme-color" content="#f00000" />
|
||||
<meta
|
||||
name="description"
|
||||
content="A free and open source web app to track completion of a living Pokédex, which works offline."
|
||||
/>
|
||||
<meta property="og:title" content="Living Dex Tracker - A free Pokédex completion tool" />
|
||||
<meta property="og:url" content="https://pokedex.jcreek.co.uk" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="A free and open source web app to track completion of a living Pokédex, which works offline."
|
||||
/>
|
||||
<link rel="canonical" href="https://pokedex.jcreek.co.uk" />
|
||||
<link rel="apple-touch-icon" href="%sveltekit.assets%/apple-touch-icon.png" />
|
||||
%sveltekit.head%
|
||||
<link rel="stylesheet" href="%sveltekit.assets%/output.css" />
|
||||
</head>
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
<script lang="ts">
|
||||
import { useRegisterSW } from 'virtual:pwa-register/svelte';
|
||||
const { needRefresh, updateServiceWorker, offlineReady } = useRegisterSW({
|
||||
onRegistered(r) {
|
||||
// uncomment following code if you want check for updates
|
||||
// r && setInterval(() => {
|
||||
// console.log('Checking for sw update')
|
||||
// r.update()
|
||||
// }, 20000 /* 20s for testing purposes */)
|
||||
console.log(`SW Registered: ${r}`);
|
||||
},
|
||||
onRegisterError(error) {
|
||||
console.log('SW registration error', error);
|
||||
}
|
||||
});
|
||||
const close = () => {
|
||||
offlineReady.set(false);
|
||||
needRefresh.set(false);
|
||||
};
|
||||
$: toast = $offlineReady || $needRefresh;
|
||||
</script>
|
||||
|
||||
{#if toast}
|
||||
<div class="pwa-toast" role="alert">
|
||||
<div class="message">
|
||||
{#if $offlineReady}
|
||||
<span> App ready to work offline </span>
|
||||
{:else}
|
||||
<span> New content available, click on reload button to update. </span>
|
||||
{/if}
|
||||
</div>
|
||||
{#if $needRefresh}
|
||||
<button on:click={() => updateServiceWorker(true)}> Reload </button>
|
||||
{/if}
|
||||
<button on:click={close}> Close </button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.pwa-toast {
|
||||
position: fixed;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
margin: 16px;
|
||||
padding: 12px;
|
||||
border: 1px solid #8885;
|
||||
border-radius: 4px;
|
||||
z-index: 2;
|
||||
text-align: left;
|
||||
box-shadow: 3px 4px 5px 0 #8885;
|
||||
background-color: white;
|
||||
}
|
||||
.pwa-toast .message {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.pwa-toast button {
|
||||
border: 1px solid #8885;
|
||||
outline: none;
|
||||
margin-right: 5px;
|
||||
border-radius: 2px;
|
||||
padding: 3px 10px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,32 @@
|
||||
/// <reference lib="WebWorker" />
|
||||
/// <reference types="vite/client" />
|
||||
/// <reference no-default-lib="true"/>
|
||||
/// <reference lib="esnext" />
|
||||
import {
|
||||
cleanupOutdatedCaches,
|
||||
createHandlerBoundToURL,
|
||||
precacheAndRoute,
|
||||
precache
|
||||
} from 'workbox-precaching';
|
||||
import { NavigationRoute, registerRoute } from 'workbox-routing';
|
||||
|
||||
declare let self: ServiceWorkerGlobalScope;
|
||||
|
||||
self.addEventListener('message', (event) => {
|
||||
if (event.data && event.data.type === 'SKIP_WAITING') self.skipWaiting();
|
||||
});
|
||||
|
||||
// Add root route to precache manifest
|
||||
precache([{ url: '/', revision: null }]);
|
||||
|
||||
// self.__WB_MANIFEST is default injection point
|
||||
precacheAndRoute(self.__WB_MANIFEST);
|
||||
|
||||
// clean old assets
|
||||
cleanupOutdatedCaches();
|
||||
|
||||
let allowlist: undefined | RegExp[];
|
||||
if (import.meta.env.DEV) allowlist = [/^\/$/];
|
||||
|
||||
// to allow work offline
|
||||
registerRoute(new NavigationRoute(createHandlerBoundToURL('/'), { allowlist }));
|
||||
@@ -6,6 +6,11 @@
|
||||
import SignIn from '$lib/components/SignIn.svelte';
|
||||
import SignOut from '$lib/components/SignOut.svelte';
|
||||
|
||||
import { pwaInfo } from 'virtual:pwa-info';
|
||||
import { pwaAssetsHead } from 'virtual:pwa-assets/head';
|
||||
|
||||
$: webManifestLink = pwaInfo ? pwaInfo.webManifest.linkTag : '';
|
||||
|
||||
export let data;
|
||||
let { supabase } = data;
|
||||
$: ({ supabase } = data);
|
||||
@@ -18,6 +23,24 @@
|
||||
|
||||
onMount(async () => {
|
||||
await getUser();
|
||||
|
||||
if (pwaInfo) {
|
||||
const { registerSW } = await import('virtual:pwa-register');
|
||||
registerSW({
|
||||
immediate: true,
|
||||
onRegistered(r) {
|
||||
// uncomment following code if you want check for updates
|
||||
// r && setInterval(() => {
|
||||
// console.log('Checking for sw update')
|
||||
// r.update()
|
||||
// }, 20000 /* 20s for testing purposes */)
|
||||
console.log(`SW Registered: ${r}`);
|
||||
},
|
||||
onRegisterError(error) {
|
||||
console.log('SW registration error', error);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
async function getUser() {
|
||||
@@ -37,6 +60,34 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
{#if pwaAssetsHead.themeColor}
|
||||
<meta name="theme-color" content={pwaAssetsHead.themeColor.content} />
|
||||
{/if}
|
||||
{#if pwaAssetsHead.description}
|
||||
<meta name="description" content={pwaAssetsHead.description.content} />
|
||||
{/if}
|
||||
{#each pwaAssetsHead.links as link}
|
||||
<link {...link} />
|
||||
{/each}
|
||||
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
|
||||
{@html webManifestLink}
|
||||
|
||||
<!-- <meta
|
||||
name="description"
|
||||
content="A free and open source web app to track completion of a living Pokédex, which works offline."
|
||||
/> -->
|
||||
<meta property="og:title" content="Living Dex Tracker - A free Pokédex completion tool" />
|
||||
<meta property="og:url" content="https://pokedex.jcreek.co.uk" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="A free and open source web app to track completion of a living Pokédex, which works offline."
|
||||
/>
|
||||
<link rel="canonical" href="https://pokedex.jcreek.co.uk" />
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
||||
<!-- <link rel="apple-touch-icon" href="%sveltekit.assets%/apple-touch-icon.png" /> -->
|
||||
</svelte:head>
|
||||
|
||||
<header>
|
||||
<div class="navbar bg-base-100">
|
||||
<div class="flex-1">
|
||||
@@ -104,3 +155,7 @@
|
||||
<a class="link link-hover">Cookie policy</a>
|
||||
</nav>
|
||||
</footer>
|
||||
|
||||
{#await import('$lib/components/pwa/ReloadPrompt.svelte') then { default: ReloadPrompt }}
|
||||
<ReloadPrompt />
|
||||
{/await}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<svelte:head>
|
||||
<title>About</title>
|
||||
<meta name="description" content="About this app" />
|
||||
</svelte:head>
|
||||
|
||||
<div class="content">
|
||||
<h1>About this app</h1>
|
||||
|
||||
<p>
|
||||
This is a <a href="https://kit.svelte.dev">SvelteKit</a> app. You can make your own by typing the
|
||||
following into your command line and following the prompts:
|
||||
</p>
|
||||
|
||||
<pre>npm create svelte@latest</pre>
|
||||
|
||||
<p>
|
||||
The page you're looking at is purely static HTML, with no client-side interactivity needed.
|
||||
Because of that, we don't need to load any JavaScript. Try viewing the page's source, or opening
|
||||
the devtools network panel and reloading.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.content {
|
||||
width: 100%;
|
||||
max-width: var(--column-width);
|
||||
margin: var(--column-margin-top) auto 0 auto;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,9 @@
|
||||
import { dev } from '$app/environment';
|
||||
|
||||
// we don't need any JS on this page, though we'll load
|
||||
// it in dev so that we get hot module replacement...
|
||||
export const csr = dev;
|
||||
|
||||
// since there's no dynamic data here, we can prerender
|
||||
// it so that it gets served as a static asset in prod
|
||||
export const prerender = true;
|
||||
@@ -1,80 +0,0 @@
|
||||
/// <reference types="@sveltejs/kit" />
|
||||
import { build, files, version } from '$service-worker';
|
||||
|
||||
// Create a unique cache name for this deployment
|
||||
const CACHE = `cache-${version}`;
|
||||
|
||||
const ASSETS = [
|
||||
...build, // the app itself
|
||||
...files // everything in `static`
|
||||
];
|
||||
|
||||
self.addEventListener('install', (event) => {
|
||||
// Create a new cache and add all files to it
|
||||
async function addFilesToCache() {
|
||||
const cache = await caches.open(CACHE);
|
||||
await cache.addAll(ASSETS);
|
||||
}
|
||||
|
||||
event.waitUntil(addFilesToCache());
|
||||
});
|
||||
|
||||
self.addEventListener('activate', (event) => {
|
||||
// Remove previous cached data from disk
|
||||
async function deleteOldCaches() {
|
||||
for (const key of await caches.keys()) {
|
||||
if (key !== CACHE) await caches.delete(key);
|
||||
}
|
||||
}
|
||||
|
||||
event.waitUntil(deleteOldCaches());
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', (event) => {
|
||||
// ignore POST requests etc
|
||||
if (event.request.method !== 'GET') return;
|
||||
|
||||
async function respond() {
|
||||
const url = new URL(event.request.url);
|
||||
const cache = await caches.open(CACHE);
|
||||
|
||||
// `build`/`files` can always be served from the cache
|
||||
if (ASSETS.includes(url.pathname)) {
|
||||
const response = await cache.match(url.pathname);
|
||||
|
||||
if (response) {
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
// for everything else, try the network first, but
|
||||
// fall back to the cache if we're offline
|
||||
try {
|
||||
const response = await fetch(event.request);
|
||||
|
||||
// if we're offline, fetch can return a value that is not a Response
|
||||
// instead of throwing - and we can't pass this non-Response to respondWith
|
||||
if (!(response instanceof Response)) {
|
||||
throw new Error('invalid response from fetch');
|
||||
}
|
||||
|
||||
if (response.status === 200) {
|
||||
cache.put(event.request, response.clone());
|
||||
}
|
||||
|
||||
return response;
|
||||
} catch (err) {
|
||||
const response = await cache.match(event.request);
|
||||
|
||||
if (response) {
|
||||
return response;
|
||||
}
|
||||
|
||||
// if there's no cache, then just error out
|
||||
// as there is nothing we can do to respond to this request
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
event.respondWith(respond());
|
||||
});
|
||||
Reference in New Issue
Block a user