mirror of
https://github.com/immich-app/immich.git
synced 2025-06-03 19:19:23 +02:00
feat: service worker cache static app resources, and all entry points
This commit is contained in:
parent
15d431ba6a
commit
9032c7e021
1 changed files with 73 additions and 2 deletions
|
@ -2,7 +2,7 @@
|
||||||
/// <reference no-default-lib="true"/>
|
/// <reference no-default-lib="true"/>
|
||||||
/// <reference lib="esnext" />
|
/// <reference lib="esnext" />
|
||||||
/// <reference lib="webworker" />
|
/// <reference lib="webworker" />
|
||||||
import { version } from '$service-worker';
|
import { build, files, version } from '$service-worker';
|
||||||
|
|
||||||
const useCache = true;
|
const useCache = true;
|
||||||
const sw = globalThis as unknown as ServiceWorkerGlobalScope;
|
const sw = globalThis as unknown as ServiceWorkerGlobalScope;
|
||||||
|
@ -11,8 +11,15 @@ const pendingLoads = new Map<string, AbortController>();
|
||||||
// Create a unique cache name for this deployment
|
// Create a unique cache name for this deployment
|
||||||
const CACHE = `cache-${version}`;
|
const CACHE = `cache-${version}`;
|
||||||
|
|
||||||
|
const APP_RESOURCES = [
|
||||||
|
...build, // the app itself
|
||||||
|
...files, // everything in `static`
|
||||||
|
];
|
||||||
|
|
||||||
sw.addEventListener('install', (event) => {
|
sw.addEventListener('install', (event) => {
|
||||||
event.waitUntil(sw.skipWaiting());
|
event.waitUntil(sw.skipWaiting());
|
||||||
|
// Create a new cache and add all files to it
|
||||||
|
event.waitUntil(addFilesToCache());
|
||||||
});
|
});
|
||||||
|
|
||||||
sw.addEventListener('activate', (event) => {
|
sw.addEventListener('activate', (event) => {
|
||||||
|
@ -26,8 +33,16 @@ sw.addEventListener('fetch', (event) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const url = new URL(event.request.url);
|
const url = new URL(event.request.url);
|
||||||
if (/^\/api\/assets\/[a-f0-9-]+\/(original|thumbnail)/.test(url.pathname)) {
|
if (APP_RESOURCES.includes(url.pathname)) {
|
||||||
|
event.respondWith(appResources(url, event));
|
||||||
|
} else if (/^\/api\/assets\/[a-f0-9-]+\/(original|thumbnail)/.test(url.pathname)) {
|
||||||
event.respondWith(immichAsset(url));
|
event.respondWith(immichAsset(url));
|
||||||
|
} else if (
|
||||||
|
/^(\/(link|auth|admin|albums|archive|buy|explore|favorites|folders|maps|memory|partners|people|photos|places|search|share|shared-links|sharing|tags|trash|user-settings|utilities))(\/.*)?$/.test(
|
||||||
|
url.pathname,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
event.respondWith(ssr(new URL(event.request.url).origin));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -39,6 +54,28 @@ async function deleteOldCaches() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function addFilesToCache() {
|
||||||
|
const cache = await caches.open(CACHE);
|
||||||
|
await cache.addAll(APP_RESOURCES);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ssr(origin: string) {
|
||||||
|
const cache = await caches.open(CACHE);
|
||||||
|
const url = new URL('/', origin);
|
||||||
|
let response = useCache ? await cache.match(url) : undefined;
|
||||||
|
if (response) {
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
response = await fetch(url);
|
||||||
|
if (!(response instanceof Response)) {
|
||||||
|
return Response.error();
|
||||||
|
}
|
||||||
|
if (response.status === 200) {
|
||||||
|
cache.put(url, response.clone());
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
async function immichAsset(url: URL) {
|
async function immichAsset(url: URL) {
|
||||||
const cache = await caches.open(CACHE);
|
const cache = await caches.open(CACHE);
|
||||||
let response = useCache ? await cache.match(url) : undefined;
|
let response = useCache ? await cache.match(url) : undefined;
|
||||||
|
@ -66,6 +103,40 @@ async function immichAsset(url: URL) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function appResources(url: URL, event: FetchEvent) {
|
||||||
|
const cache = await caches.open(CACHE);
|
||||||
|
// `build`/`files` can always be served from the cache
|
||||||
|
if (APP_RESOURCES.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 TypeError('invalid response from fetch');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.status === 200) {
|
||||||
|
cache.put(event.request, response.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
} catch {
|
||||||
|
const response = await cache.match(event.request);
|
||||||
|
if (response) {
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
// if there's no cache, then just error out
|
||||||
|
return Response.error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const broadcast = new BroadcastChannel('immich');
|
const broadcast = new BroadcastChannel('immich');
|
||||||
// eslint-disable-next-line unicorn/prefer-add-event-listener
|
// eslint-disable-next-line unicorn/prefer-add-event-listener
|
||||||
broadcast.onmessage = (event) => {
|
broadcast.onmessage = (event) => {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue