mirror of
https://github.com/GoogleChromeLabs/squoosh.git
synced 2025-11-11 16:26:20 +00:00
* Quick test * More testing * More testing * Removing transfer for now * Changing name so it's easier to tell them apart when installed * Disable minification to ease debugging * Adding navigate lock * lol oops * Add minifying back * Removing minification again, for debugging * Removing broadcast channel bits, to simplify the code * Revert "Removing broadcast channel bits, to simplify the code" This reverts commit 0b2a3ecf2986aae0dd65fdd1ddda2bd9e4e1eac7. * I think this fixes it * Refactor * Suppress flash of home screen during share target * Almost ready, so switching to real name * Removing log * Ahh yes the trailing comma thing * Removing use of BroadcastChannel * Reducing ternary
150 lines
4.6 KiB
TypeScript
150 lines
4.6 KiB
TypeScript
import webpDataUrl from 'url-loader!../codecs/tiny.webp';
|
|
|
|
// Give TypeScript the correct global.
|
|
declare var self: ServiceWorkerGlobalScope;
|
|
|
|
export function cacheOrNetwork(event: FetchEvent): void {
|
|
event.respondWith(async function () {
|
|
const cachedResponse = await caches.match(event.request, { ignoreSearch: true });
|
|
return cachedResponse || fetch(event.request);
|
|
}());
|
|
}
|
|
|
|
export function cacheOrNetworkAndCache(event: FetchEvent, cacheName: string): void {
|
|
event.respondWith(async function () {
|
|
const { request } = event;
|
|
// Return from cache if possible.
|
|
const cachedResponse = await caches.match(request);
|
|
if (cachedResponse) return cachedResponse;
|
|
|
|
// Else go to the network.
|
|
const response = await fetch(request);
|
|
const responseToCache = response.clone();
|
|
|
|
event.waitUntil(async function () {
|
|
// Cache what we fetched.
|
|
const cache = await caches.open(cacheName);
|
|
await cache.put(request, responseToCache);
|
|
}());
|
|
|
|
// Return the network response.
|
|
return response;
|
|
}());
|
|
}
|
|
|
|
export function serveShareTarget(event: FetchEvent): void {
|
|
const dataPromise = event.request.formData();
|
|
|
|
// Redirect so the user can refresh the page without resending data.
|
|
// @ts-ignore It doesn't like me giving a response to respondWith, although it's allowed.
|
|
event.respondWith(Response.redirect('/?share-target'));
|
|
|
|
event.waitUntil(async function () {
|
|
// The page sends this message to tell the service worker it's ready to receive the file.
|
|
await nextMessage('share-ready');
|
|
const client = await self.clients.get(event.resultingClientId);
|
|
const data = await dataPromise;
|
|
const file = data.get('file');
|
|
client.postMessage({ file, action: 'load-image' });
|
|
}());
|
|
}
|
|
|
|
export function cleanupCache(event: FetchEvent, cacheName: string, keepAssets: string[]) {
|
|
event.waitUntil(async function () {
|
|
const cache = await caches.open(cacheName);
|
|
|
|
// Clean old entries from the dynamic cache.
|
|
const requests = await cache.keys();
|
|
const promises = requests.map((cachedRequest) => {
|
|
// Get pathname without leading /
|
|
const assetPath = new URL(cachedRequest.url).pathname.slice(1);
|
|
// If it isn't one of our keepAssets, we don't need it anymore.
|
|
if (!keepAssets.includes(assetPath)) return cache.delete(cachedRequest);
|
|
});
|
|
|
|
await Promise.all<any>(promises);
|
|
}());
|
|
}
|
|
|
|
function getAssetsWithPrefix(assets: string[], prefixes: string[]) {
|
|
return assets.filter(
|
|
asset => prefixes.some(prefix => asset.startsWith(prefix)),
|
|
);
|
|
}
|
|
|
|
export async function cacheBasics(cacheName: string, buildAssets: string[]) {
|
|
const toCache = ['/', '/assets/favicon.ico'];
|
|
|
|
const prefixesToCache = [
|
|
// Main app JS & CSS:
|
|
'main-app.',
|
|
// Service worker handler:
|
|
'offliner.',
|
|
// Little icons for the demo images on the homescreen:
|
|
'icon-demo-',
|
|
// Site logo:
|
|
'logo.',
|
|
];
|
|
|
|
const prefixMatches = getAssetsWithPrefix(buildAssets, prefixesToCache);
|
|
|
|
toCache.push(...prefixMatches);
|
|
|
|
const cache = await caches.open(cacheName);
|
|
await cache.addAll(toCache);
|
|
}
|
|
|
|
export async function cacheAdditionalProcessors(cacheName: string, buildAssets: string[]) {
|
|
let toCache = [];
|
|
|
|
const prefixesToCache = [
|
|
// Worker which handles image processing:
|
|
'processor-worker.',
|
|
// processor-worker imports:
|
|
'process-',
|
|
];
|
|
|
|
const prefixMatches = getAssetsWithPrefix(buildAssets, prefixesToCache);
|
|
const wasm = buildAssets.filter(asset => asset.endsWith('.wasm'));
|
|
|
|
toCache.push(...prefixMatches, ...wasm);
|
|
|
|
const supportsWebP = await (async () => {
|
|
if (!self.createImageBitmap) return false;
|
|
const response = await fetch(webpDataUrl);
|
|
const blob = await response.blob();
|
|
return createImageBitmap(blob).then(() => true, () => false);
|
|
})();
|
|
|
|
// No point caching the WebP decoder if it's supported natively:
|
|
if (supportsWebP) {
|
|
toCache = toCache.filter(asset => !/webp[\-_]dec/.test(asset));
|
|
}
|
|
|
|
const cache = await caches.open(cacheName);
|
|
await cache.addAll(toCache);
|
|
}
|
|
|
|
const nextMessageResolveMap = new Map<string, (() => void)[]>();
|
|
|
|
/**
|
|
* Wait on a message with a particular event.data value.
|
|
*
|
|
* @param dataVal The event.data value.
|
|
*/
|
|
function nextMessage(dataVal: string): Promise<void> {
|
|
return new Promise((resolve) => {
|
|
if (!nextMessageResolveMap.has(dataVal)) {
|
|
nextMessageResolveMap.set(dataVal, []);
|
|
}
|
|
nextMessageResolveMap.get(dataVal)!.push(resolve);
|
|
});
|
|
}
|
|
|
|
self.addEventListener('message', (event) => {
|
|
const resolvers = nextMessageResolveMap.get(event.data);
|
|
if (!resolvers) return;
|
|
nextMessageResolveMap.delete(event.data);
|
|
for (const resolve of resolvers) resolve();
|
|
});
|