more work on service worker

This commit is contained in:
Nolan Lawson 2018-01-14 17:13:42 -08:00
parent 0b442bb2a6
commit 01243ba4c1
3 changed files with 84 additions and 28 deletions

View file

@ -0,0 +1,14 @@
const importURLSearchParams = () => import(
/* webpackChunkName: 'url-search-params' */ 'url-search-params'
).then(Params => {
window.URLSearchParams = Params
Object.defineProperty(window.URL.prototype, 'searchParams', {
get() {
return new Params(this.search)
}
})
})
export {
importURLSearchParams
}

View file

@ -1,16 +1,19 @@
import { init } from 'sapper/runtime.js'; import { init } from 'sapper/runtime.js'
import toast from '../routes/_utils/toast.js'
// polyfills // polyfills
Promise.all([ Promise.all([
typeof URLSearchParams === 'undefined' && import(/* webpackChunkName: 'url-search-params' */ 'url-search-params').then(Params => { typeof URLSearchParams === 'undefined' && importURLParams()
window.URLSearchParams = Params
Object.defineProperty(window.URL.prototype, 'searchParams', {
get() {
return new Params(this.search)
}
})
})
]).then(() => { ]).then(() => {
// `routes` is an array of route objects injected by Sapper // `routes` is an array of route objects injected by Sapper
init(document.querySelector('#sapper'), __routes__) init(document.querySelector('#sapper'), __routes__)
if (navigator.serviceWorker && navigator.serviceWorker.controller) {
navigator.serviceWorker.controller.onstatechange = (e) => {
if (e.target.state === 'redundant') {
toast.say('App update available. Reload to update.');
}
}
}
}) })

View file

@ -36,8 +36,18 @@ self.addEventListener('activate', event => {
) )
}) })
const NETWORK_ONLY = [
'/oauth'
]
const CACHE_FIRST = [
'/api/v1/accounts/verify_credentials',
'/system/accounts/avatars'
]
self.addEventListener('fetch', event => { self.addEventListener('fetch', event => {
const url = new URL(event.request.url) const req = event.request
const url = new URL(req.url)
// don't try to handle e.g. data: URIs // don't try to handle e.g. data: URIs
if (!url.protocol.startsWith('http')) { if (!url.protocol.startsWith('http')) {
@ -46,7 +56,7 @@ self.addEventListener('fetch', event => {
// always serve assets and webpack-generated files from cache // always serve assets and webpack-generated files from cache
if (cached.has(url.pathname)) { if (cached.has(url.pathname)) {
event.respondWith(caches.match(event.request)) event.respondWith(caches.match(req))
return return
} }
@ -55,30 +65,59 @@ self.addEventListener('fetch', event => {
// app, but if it's right for yours then uncomment this section // app, but if it's right for yours then uncomment this section
if (url.origin === self.origin && routes.find(route => route.pattern.test(url.pathname))) { if (url.origin === self.origin && routes.find(route => route.pattern.test(url.pathname))) {
event.respondWith(caches.match('/index.html')); event.respondWith(caches.match('/index.html'))
return; return
}
// Non-GET and for certain endpoints (e.g. OAuth), go network-only
if (req.method !== 'GET' ||
NETWORK_ONLY.some(pattern => url.pathname.startsWith(pattern))) {
console.log('Using network-only for', url.href)
event.respondWith(fetch(req))
return
}
// For these, go cache-first.
if (CACHE_FIRST.some(pattern => url.pathname.startsWith(pattern))) {
console.log('Using cache-first for', url.href)
event.respondWith(caches
.open(`offline${timestamp}`)
.then(async cache => {
let response = await cache.match(req)
if (response) {
// update asynchronously
fetch(req).then(response => {
cache.put(req, response.clone())
})
return response
}
response = await fetch(req)
cache.put(req, response.clone())
return response
}))
return
} }
// for everything else, try the network first, falling back to // for everything else, try the network first, falling back to
// cache if the user is offline. (If the pages never change, you // cache if the user is offline. (If the pages never change, you
// might prefer a cache-first approach to a network-first one.) // might prefer a cache-first approach to a network-first one.)
event.respondWith( event.respondWith(caches
caches .open(`offline${timestamp}`)
.open(`offline${timestamp}`) .then(async cache => {
.then(async cache => { try {
try { console.log('Using network-first for', url.href)
const response = await fetch(event.request) const response = await fetch(req)
cache.put(event.request, response.clone()) cache.put(req, response.clone())
return response
} catch (err) {
const response = await cache.match(req)
if (response) {
return response return response
} catch (err) {
const response = await cache.match(event.request)
if (response) {
return response
}
throw err
} }
})
throw err
}
})
) )
}) })