0 directories, 2 files

pwa

Home / tinai / pwa
/**
 * Updates the loading screen progress bar and percent label.
 * No-op once the app has faded the loader out.
 * @param {number} done - Number of files refreshed so far.
 * @param {number} total - Total number of files to refresh.
 * @returns {void}
 */
function updateLoaderProgress(done, total) {
	const percent = Math.round((done / total) * 100);
	const label = document.querySelector('.page-loader-percent');
	if (label) {
		label.textContent = `${percent}%`;
	}
	const fill = document.querySelector('.page-loader-bar-fill');
	if (fill) {
		fill.style.width = `${percent}%`;
	}
}

/**
 * Fetches the asset manifest from pwa/manifest.php and revalidates each
 * file. Requests pass through the service worker's network-first handler,
 * so every response refreshes the offline fallback cache, covering .js,
 * .css and .json files. Progress is reported to the loading screen.
 * @returns {Promise<void>}
 */
async function refreshAssets() {
	let files;
	try {
		const response = await fetch('./pwa/manifest.php');
		if (!response.ok) return;
		files = await response.json();
	} catch (error) {
		return;
	}
	for (let i = 0; i < files.length; i++) {
		try {
			// 'reload' bypasses the browser's heuristic HTTP cache and always
			// revalidates against the network, so the service worker's offline
			// cache is refreshed with the current file (keeping the same URL
			// as cache key).
			await fetch(files[i], { cache: 'reload' });
		} catch (error) {
			// Offline: the service worker serves the cached copy.
		}
		updateLoaderProgress(i + 1, files.length);
	}
}

/**
 * Registers the root service worker and handles cache invalidation.
 * The browser re-checks sw.js on every load; when an updated worker
 * takes over an already-controlled page, the page reloads once so the
 * new code and assets are picked up behind the loading screen.
 * The asset refresh is skipped when 'pwa-skip-refresh' is set to
 * 'switching' in sessionStorage (done by user switching, which reloads
 * into an unchanged app; index.php displays "Switching User..." for it).
 * @returns {Promise<void>}
 */
export async function initPWA() {
	if (!('serviceWorker' in navigator)) return;

	const hadController = Boolean(navigator.serviceWorker.controller);

	try {
		const registration = await navigator.serviceWorker.register('./sw.js');
		navigator.serviceWorker.addEventListener('controllerchange', () => {
			if (hadController) {
				window.location.reload();
			}
		});
		registration.update().catch((error) => console.error('PWA update check failed:', error));
		await navigator.serviceWorker.ready;
		if (sessionStorage.getItem('pwa-skip-refresh') === 'switching') {
			sessionStorage.removeItem('pwa-skip-refresh');
			return;
		}
		refreshAssets();
	} catch (error) {
		console.error('PWA registration failed:', error);
	}
}
🌐
pwa.js ×
Type: Web, text/plain
2.76 Kilobytes
Last Modified 2026-11-04 09:48:28
⬇ Download File