Last active
February 24, 2021 01:07
-
-
Save Warr1024/1670c8a5d21f66ffc599a6f51867dbee to your computer and use it in GitHub Desktop.
TiddlyWiki5 Offline ServiceWorker
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Service worker that implements caching and offline fallback for a | |
TiddlyWiki5 instance with tiddlyweb saving hosted on nodejs. | |
This gives you the best of both worlds: a shared, synchronized wiki that | |
you can edit from anywhere and automatically syncs across multiple | |
devices, AND a fallback local version that you can still access when | |
offline, and will queue up changes to be uploaded when you're back | |
online later. | |
When you're offline, the wiki will still load, and you'll still have | |
access to all the tiddlers you've already loaded, but the page will be | |
aware it's offline and will throw network connection errors, so you'll | |
want to tweak the presentation of errors inside TW5 so they're less | |
obtrusive and you can work around then, but you'll still want to be | |
aware that your changes aren't saved yet. | |
Saving works when you return online, but only if the page is actually | |
loaded a the time, i.e. the service worker can't queue up background | |
syncs and relies on the front-end page trying to push a save when | |
the network is actually available. Background sync for service workers | |
is not standards-track yet, and even if it were, it would probably | |
require more extensive changes to TW5 to make it | |
background-sync-API-aware. | |
As it is, this service worker provides a reasonable experience with a | |
completely unmodified TW5 nodejs instance. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
const log = msg => console.log(`service-worker: ${msg}`); | |
const listener = (name, func) => self.addEventListener(name, evt => { | |
log(name); | |
evt.waitUntil((async () => await func(evt))()); | |
}); | |
listener('install', () => self.skipWaiting()); | |
listener('activate', async () => { | |
await self.clients.claim(); | |
for (let c of await self.clients.matchAll()) | |
c.postMessage('reload'); | |
}); | |
listener('fetch', async evt => { | |
const req = evt.request; | |
const rpt = s => log(`fetch ${req.mode} ${req.method} ${req.url} -> ${s}`); | |
const fetching = fetch(req); | |
// API write requests go online only. | |
if (req.method !== 'GET') { | |
rpt('nocache'); | |
return evt.respondWith(fetching); | |
} | |
// API read requests try online first. | |
if (/\/status$/.test(req.url) || | |
/\/recipes\/.*\?/.test(req.url)) | |
return evt.respondWith((async () => { | |
const cache = await caches.open('main'); | |
let resp; | |
try { resp = await fetching; } | |
catch(e) { } | |
if(!resp || !resp.ok) { | |
const found = await cache.match(req); | |
rpt(found ? 'fallback' : 'fail'); | |
return found || resp || new Response({ status: 400 }); | |
} | |
rpt('online'); | |
await cache.put(req, resp); | |
return await cache.match(req); | |
})()); | |
// All other requests always use cache first. | |
return evt.respondWith((async () => { | |
const cache = await caches.open('main'); | |
const found = await cache.match(req); | |
if (found) { | |
rpt('cached'); | |
fetching.then(resp => { | |
rpt('update'); | |
cache.put(req, resp); | |
}); | |
return found; | |
} | |
const resp = await fetching; | |
if (!resp.ok) { | |
rpt('!ok'); | |
return resp; | |
} | |
rpt('fresh'); | |
await cache.put(req, resp); | |
return await cache.match(req); | |
})()); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment