@jorsek/ezd-client
Version:
115 lines (86 loc) • 3.43 kB
text/typescript
import limiter from "p-limit";
import { Client, INavTree } from "src";
import { Workbox } from "workbox-window";
export const getOfflineStatus = () => {
const val = window.localStorage.getItem("prefetch_status");
if (val === "complete") {
return "COMPLETE";
} else {
return "INCOMPLETE";
}
};
export const prefetchAll = async ({ status_callback, client, parallelism = 10 }: { status_callback: (status: string) => void; client: Client; parallelism?: number }) => {
if (getOfflineStatus() === "COMPLETE") {
status_callback("Ready");
return;
}
const do_fetch = async () => {
const paths = ["/"];
const hidden_fetcher = document.createElement("div");
hidden_fetcher.hidden = true;
const limit = limiter(parallelism);
const sections = await client.content.getSections();
let processed = 0;
let total = 0;
const section_promise_map: { [key: string]: Array<Promise<void>> } = {};
const loadLeaf = async (section, leaf: {href: string}) => {
try {
const content = await client.content.getContent(leaf.href);
paths.push(`/content/${leaf.href}`);
hidden_fetcher.innerHTML = content.content;
processed++;
status_callback(`Processing ${section}: ${processed}/${total}`);
} catch (e) {
// womp womp, still try and load stuff anyway
}
};
const handleTree = (section, tree: INavTree) => {
if (!section_promise_map[section]) {
section_promise_map[section] = [];
}
section_promise_map[section].push(limit(() => loadLeaf(section, tree)));
total++;
for (const child of tree.children) {
handleTree(section, child);
}
};
for (const section of sections) {
const navTree = await client.content.getNavTree(section.href);
if (!section_promise_map[section.title]) {
section_promise_map[section.title] = [];
}
section_promise_map[section.title].push(limit(() => loadLeaf(section.title, {href: section.href})));
total++;
handleTree(section.title, navTree);
}
for (const [section_name, promises] of Object.entries(section_promise_map)) {
await Promise.all(promises);
}
return paths;
// status_callback("Offline Ready!");
};
const wb = new Workbox("/service-worker.js");
wb.addEventListener("installed", (event) => {
// @ts-ignore
if (!event.isUpdate) {
status_callback("First Service Worker load!");
window.location.reload();
}
});
status_callback("Waiting for sw to control page...");
// tslint:disable-next-line: no-floating-promises
wb.register();
await wb.controlling;
const urlsToCache = await do_fetch();
status_callback(`Prefetching ${urlsToCache.length} content pages...`);
// @ts-ignore
const success = await wb.messageSW({
type: "CACHE_URLS",
payload: {
urlsToCache,
},
});
status_callback(`Prefetch ${success ? "success" : "failure"}`);
window.localStorage.setItem("prefetch_status", "complete");
status_callback("All set!");
};