cache routes modules
This commit is contained in:
		@@ -8,6 +8,20 @@ if ("serviceWorker" in navigator) {
 | 
			
		||||
		try {
 | 
			
		||||
			await navigator.serviceWorker.register("/entry.worker.js");
 | 
			
		||||
			await navigator.serviceWorker.ready;
 | 
			
		||||
 | 
			
		||||
			if (navigator.serviceWorker.controller) {
 | 
			
		||||
				return navigator.serviceWorker.controller.postMessage({
 | 
			
		||||
					type: "SYNC_REMIX_MANIFEST",
 | 
			
		||||
					manifest: window.__remixManifest,
 | 
			
		||||
				});
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			navigator.serviceWorker.addEventListener("controllerchange", () => {
 | 
			
		||||
				navigator.serviceWorker.controller?.postMessage({
 | 
			
		||||
					type: "SYNC_REMIX_MANIFEST",
 | 
			
		||||
					manifest: window.__remixManifest,
 | 
			
		||||
				});
 | 
			
		||||
			});
 | 
			
		||||
		} catch (error) {
 | 
			
		||||
			console.error("Service worker registration failed", error, (error as Error).name);
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ import handleActivate from "./service-worker/activate";
 | 
			
		||||
import handlePush from "./service-worker/push";
 | 
			
		||||
import handleNotificationClick from "./service-worker/notification-click";
 | 
			
		||||
import handleFetch from "./service-worker/fetch";
 | 
			
		||||
import handleMessage from "./service-worker/message";
 | 
			
		||||
 | 
			
		||||
declare let self: ServiceWorkerGlobalScope;
 | 
			
		||||
 | 
			
		||||
@@ -24,6 +25,10 @@ self.addEventListener("notificationclick", (event) => {
 | 
			
		||||
	event.waitUntil(handleNotificationClick(event));
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
self.addEventListener("message", (event) => {
 | 
			
		||||
	event.waitUntil(handleMessage(event));
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
self.addEventListener("fetch", (event) => {
 | 
			
		||||
	event.respondWith(handleFetch(event));
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										110
									
								
								app/service-worker/message.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								app/service-worker/message.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,110 @@
 | 
			
		||||
import type { AssetsManifest } from "@remix-run/react/entry";
 | 
			
		||||
import type { EntryRoute } from "@remix-run/react/routes";
 | 
			
		||||
 | 
			
		||||
import { ASSET_CACHE } from "./cache-utils";
 | 
			
		||||
 | 
			
		||||
declare let self: ServiceWorkerGlobalScope;
 | 
			
		||||
 | 
			
		||||
export default async function handleMessage(event: ExtendableMessageEvent) {
 | 
			
		||||
	if (event.data.type === "SYNC_REMIX_MANIFEST") {
 | 
			
		||||
		return handleSyncRemixManifest(event);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function handleSyncRemixManifest(event: ExtendableMessageEvent) {
 | 
			
		||||
	console.debug("Caching routes modules");
 | 
			
		||||
 | 
			
		||||
	await cacheStaticAssets(event.data.manifest);
 | 
			
		||||
 | 
			
		||||
	// await cacheConversations(manifest);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function cacheStaticAssets(manifest: AssetsManifest) {
 | 
			
		||||
	const cachePromises: Map<string, Promise<void>> = new Map();
 | 
			
		||||
	const assetCache = await caches.open(ASSET_CACHE);
 | 
			
		||||
	const routes = [...Object.values(manifest.routes), manifest.entry];
 | 
			
		||||
 | 
			
		||||
	for (const route of routes) {
 | 
			
		||||
		if (!cachePromises.has(route.module)) {
 | 
			
		||||
			cachePromises.set(route.module, cacheAsset(route.module));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (route.imports) {
 | 
			
		||||
			for (const assetUrl of route.imports) {
 | 
			
		||||
				if (!cachePromises.has(assetUrl)) {
 | 
			
		||||
					cachePromises.set(assetUrl, cacheAsset(assetUrl));
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	await Promise.all(cachePromises.values());
 | 
			
		||||
 | 
			
		||||
	async function cacheAsset(assetUrl: string) {
 | 
			
		||||
		if (await assetCache.match(assetUrl)) {
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		console.debug("Caching asset", assetUrl);
 | 
			
		||||
		return assetCache.add(assetUrl).catch((error) => {
 | 
			
		||||
			console.debug(`Failed to cache asset ${assetUrl}:`, error);
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*async function cacheConversations(manifest: AssetsManifest) {
 | 
			
		||||
	console.log("caching conversation");
 | 
			
		||||
	const cachePromises: Map<string, Promise<void>> = new Map();
 | 
			
		||||
	const dataCache = await caches.open(DATA_CACHE);
 | 
			
		||||
	const messagesResponse = await getMessagesResponse();
 | 
			
		||||
	if (!messagesResponse) {
 | 
			
		||||
		console.log("rip never happened");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const { json } = await messagesResponse.json();
 | 
			
		||||
	const recipients = Object.keys(json.conversations);
 | 
			
		||||
	recipients.forEach((recipient) => cacheConversation(recipient));
 | 
			
		||||
 | 
			
		||||
	await Promise.all(cachePromises.values());
 | 
			
		||||
 | 
			
		||||
	function getMessagesResponse() {
 | 
			
		||||
		const route = manifest.routes["routes/__app/messages"];
 | 
			
		||||
		const pathname = getPathname(route, manifest);
 | 
			
		||||
		const params = new URLSearchParams({ _data: route.id });
 | 
			
		||||
		const search = `?${params.toString()}`;
 | 
			
		||||
		const url = pathname + search;
 | 
			
		||||
		return dataCache.match(url);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	function cacheConversation(recipient: string) {
 | 
			
		||||
		const route = manifest.routes["routes/__app/messages.$recipient"];
 | 
			
		||||
		const pathname = getPathname(route, manifest).replace(":recipient", encodeURIComponent(recipient));
 | 
			
		||||
		const params = new URLSearchParams({ _data: route.id });
 | 
			
		||||
		const search = `?${params.toString()}`;
 | 
			
		||||
		const url = pathname + search;
 | 
			
		||||
		if (!cachePromises.has(url)) {
 | 
			
		||||
			console.debug("Caching conversation with", recipient);
 | 
			
		||||
			cachePromises.set(
 | 
			
		||||
				url,
 | 
			
		||||
				dataCache.add(url).catch((error) => {
 | 
			
		||||
					console.debug(`Failed to cache data for ${url}:`, error);
 | 
			
		||||
				}),
 | 
			
		||||
			);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}*/
 | 
			
		||||
 | 
			
		||||
function getPathname(route: EntryRoute, manifest: AssetsManifest) {
 | 
			
		||||
	let pathname = "";
 | 
			
		||||
	if (route.path && route.path.length > 0) {
 | 
			
		||||
		pathname = "/" + route.path;
 | 
			
		||||
	}
 | 
			
		||||
	if (route.parentId) {
 | 
			
		||||
		const parentPath = getPathname(manifest.routes[route.parentId], manifest);
 | 
			
		||||
		if (parentPath) {
 | 
			
		||||
			pathname = parentPath + pathname;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return pathname;
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user