perf: download and cache polyfills on-the-fly (#814)
* perf: download and cache polyfills on-the-fly * fixup the localhost switch for service worker, does nothing
This commit is contained in:
parent
dbd6c35a88
commit
260f6acf0e
|
@ -143,6 +143,7 @@
|
|||
"ignore": [
|
||||
"dist",
|
||||
"src/routes/_utils/asyncModules.js",
|
||||
"src/routes/_utils/asyncPolyfills.js",
|
||||
"src/routes/_components/dialog/asyncDialogs.js"
|
||||
]
|
||||
},
|
||||
|
|
|
@ -4,26 +4,6 @@ export const importTimeline = () => import(
|
|||
/* webpackChunkName: 'Timeline' */ '../_components/timeline/Timeline.html'
|
||||
).then(getDefault)
|
||||
|
||||
export const importIntersectionObserver = () => import(
|
||||
/* webpackChunkName: 'intersection-observer' */ 'intersection-observer'
|
||||
)
|
||||
|
||||
export const importRequestIdleCallback = () => import(
|
||||
/* webpackChunkName: 'requestidlecallback' */ 'requestidlecallback'
|
||||
)
|
||||
|
||||
export const importWebAnimationPolyfill = () => import(
|
||||
/* webpackChunkName: 'web-animations-js' */ 'web-animations-js'
|
||||
)
|
||||
|
||||
export const importIndexedDBGetAllShim = () => import(
|
||||
/* webpackChunkName: 'indexeddb-getall-shim' */ 'indexeddb-getall-shim'
|
||||
)
|
||||
|
||||
export const importCustomElementsPolyfill = () => import(
|
||||
/* webpackChunkName: '@webcomponents/custom-elements' */ '@webcomponents/custom-elements'
|
||||
)
|
||||
|
||||
export const importPageLifecycle = () => import(
|
||||
/* webpackChunkName: 'page-lifecycle' */ 'page-lifecycle/dist/lifecycle.mjs'
|
||||
).then(getDefault)
|
||||
|
|
19
src/routes/_utils/asyncPolyfills.js
Normal file
19
src/routes/_utils/asyncPolyfills.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
export const importIntersectionObserver = () => import(
|
||||
/* webpackChunkName: '$polyfill$-intersection-observer' */ 'intersection-observer'
|
||||
)
|
||||
|
||||
export const importRequestIdleCallback = () => import(
|
||||
/* webpackChunkName: '$polyfill$-requestidlecallback' */ 'requestidlecallback'
|
||||
)
|
||||
|
||||
export const importWebAnimationPolyfill = () => import(
|
||||
/* webpackChunkName: '$polyfill$-web-animations-js' */ 'web-animations-js'
|
||||
)
|
||||
|
||||
export const importIndexedDBGetAllShim = () => import(
|
||||
/* webpackChunkName: '$polyfill$-indexeddb-getall-shim' */ 'indexeddb-getall-shim'
|
||||
)
|
||||
|
||||
export const importCustomElementsPolyfill = () => import(
|
||||
/* webpackChunkName: '$polyfill$-@webcomponents/custom-elements' */ '@webcomponents/custom-elements'
|
||||
)
|
|
@ -4,7 +4,7 @@ import {
|
|||
importIntersectionObserver,
|
||||
importRequestIdleCallback,
|
||||
importWebAnimationPolyfill
|
||||
} from './asyncModules'
|
||||
} from './asyncPolyfills'
|
||||
|
||||
export function loadPolyfills () {
|
||||
return Promise.all([
|
||||
|
|
|
@ -10,7 +10,7 @@ function onUpdateFound (registration) {
|
|||
})
|
||||
}
|
||||
|
||||
if (!location.origin.match('localhost') && 'serviceWorker' in navigator) {
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.register('/service-worker.js').then(registration => {
|
||||
registration.addEventListener('updatefound', () => onUpdateFound(registration))
|
||||
})
|
||||
|
|
|
@ -4,6 +4,11 @@ import {
|
|||
routes as __routes__
|
||||
} from '../__sapper__/service-worker.js'
|
||||
|
||||
import {
|
||||
get,
|
||||
post
|
||||
} from './routes/_utils/ajax'
|
||||
|
||||
const timestamp = process.env.SAPPER_TIMESTAMP
|
||||
const ASSETS = `assets_${timestamp}`
|
||||
const WEBPACK_ASSETS = `webpack_assets_${timestamp}`
|
||||
|
@ -17,7 +22,8 @@ const assets = __assets__
|
|||
// `shell` is an array of all the files generated by webpack
|
||||
// also contains '/index.html' for some reason
|
||||
const webpackAssets = __shell__
|
||||
.filter(filename => !filename.endsWith('.map'))
|
||||
.filter(filename => !filename.endsWith('.map')) // don't bother with sourcemaps
|
||||
.filter(filename => !filename.includes('$polyfill$')) // polyfills are cached on-demand
|
||||
|
||||
// `routes` is an array of `{ pattern: RegExp }` objects that
|
||||
// match the pages in your src
|
||||
|
@ -93,6 +99,13 @@ self.addEventListener('fetch', event => {
|
|||
return response
|
||||
}
|
||||
}
|
||||
// for polyfills, cache them on-the-fly
|
||||
if (url.pathname.includes('$polyfill$')) {
|
||||
let response = await fetch(req)
|
||||
// cache asynchronously, don't wait
|
||||
caches.open(WEBPACK_ASSETS).then(cache => cache.put(req, response))
|
||||
return response.clone()
|
||||
}
|
||||
}
|
||||
|
||||
// for everything else, go network-only
|
||||
|
@ -247,62 +260,3 @@ self.addEventListener('notificationclick', event => {
|
|||
}
|
||||
})())
|
||||
})
|
||||
|
||||
// Copy-paste from ajax.js
|
||||
async function get (url, headers, options) {
|
||||
return _fetch(url, makeFetchOptions('GET', headers), options)
|
||||
}
|
||||
|
||||
async function post (url, body, headers, options) {
|
||||
return _putOrPostOrPatch('POST', url, body, headers, options)
|
||||
}
|
||||
|
||||
async function _putOrPostOrPatch (method, url, body, headers, options) {
|
||||
let fetchOptions = makeFetchOptions(method, headers)
|
||||
if (body) {
|
||||
if (body instanceof FormData) {
|
||||
fetchOptions.body = body
|
||||
} else {
|
||||
fetchOptions.body = JSON.stringify(body)
|
||||
fetchOptions.headers['Content-Type'] = 'application/json'
|
||||
}
|
||||
}
|
||||
return _fetch(url, fetchOptions, options)
|
||||
}
|
||||
|
||||
async function _fetch (url, fetchOptions, options) {
|
||||
let response
|
||||
if (options && options.timeout) {
|
||||
response = await fetchWithTimeout(url, fetchOptions, options.timeout)
|
||||
} else {
|
||||
response = await fetch(url, fetchOptions)
|
||||
}
|
||||
return throwErrorIfInvalidResponse(response)
|
||||
}
|
||||
|
||||
async function throwErrorIfInvalidResponse (response) {
|
||||
let json = await response.json()
|
||||
if (response.status >= 200 && response.status < 300) {
|
||||
return json
|
||||
}
|
||||
if (json && json.error) {
|
||||
throw new Error(response.status + ': ' + json.error)
|
||||
}
|
||||
throw new Error('Request failed: ' + response.status)
|
||||
}
|
||||
|
||||
function fetchWithTimeout (url, fetchOptions, timeout) {
|
||||
return new Promise((resolve, reject) => {
|
||||
fetch(url, fetchOptions).then(resolve, reject)
|
||||
setTimeout(() => reject(new Error(`Timed out after ${timeout / 1000} seconds`)), timeout)
|
||||
})
|
||||
}
|
||||
|
||||
function makeFetchOptions (method, headers) {
|
||||
return {
|
||||
method,
|
||||
headers: Object.assign(headers || {}, {
|
||||
'Accept': 'application/json'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue