Skip to content

Instantly share code, notes, and snippets.

@ThingEngineer
Created March 7, 2024 17:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ThingEngineer/c6d46db6eb8640c7d32e44ee5b4c74fe to your computer and use it in GitHub Desktop.
Save ThingEngineer/c6d46db6eb8640c7d32e44ee5b4c74fe to your computer and use it in GitHub Desktop.
SvelteKit Minimal PWA Install Button and Service Worker Auto Update Prompt

SvelteKit Minimal PWA Install Button and Service Worker Auto Update Prompt

How to use

Add this to your root +layout.svelte in your already working PWA

<script>
	import { beforeNavigate } from '$app/navigation';
	import { updated } from '$app/stores';
	import { onMount } from 'svelte';

	// Check for updates and fallback to full page navigation to refresh the app
	beforeNavigate(async ({ willUnload, to }) => {
		if ($updated && !willUnload && to?.url) {
			location.href = to.url.href;
		}
	});

	async function detectSWUpdate() {
		const registration = await navigator.serviceWorker.ready;
		registration.addEventListener('updatefound', () => {
			const newWorker = registration.installing;
			if (!newWorker) return;
			newWorker.addEventListener('statechange', () => {
				if (newWorker.state === 'installed') {
					if (navigator.serviceWorker.controller) {
						console.log('New update available');
						if (confirm('Update available! \nRefresh to update?')) {
							newWorker.postMessage({ type: 'skipWaiting' });
							window.location.reload();
						}
					} else {
						console.log('Content is now available offline!');
					}
				}
			});
		});
	}

	/**
	 * @type {Event | undefined}
	 */
	let deferredInstallEvent;

	onMount(() => {
		detectSWUpdate
  
		window.addEventListener('beforeinstallprompt', (e) => {
			e.preventDefault();
			deferredInstallEvent = e;
		});
	});

	async function handleInstall() {
		// @ts-ignore
		deferredInstallEvent?.prompt();
		// @ts-ignore
		const { choice } = await deferredInstallEvent?.userChoice;
		if (choice.outcome === 'accepted') {
			// User accepted to install the application
		} else {
			// User dismissed the prompt
		}
		deferredInstallEvent = undefined;
	}
</script>
{#if deferredInstallEvent}
	<button
		class="install-button"
		on:click={handleInstall}>Install App</button
	>
{/if}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment