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
					
				
					 6 changed files with 36 additions and 82 deletions
				
			
		| 
						 | 
				
			
			@ -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…
	
	Add table
		
		Reference in a new issue