perf: use lite web animations polyfill (#1011)

This commit is contained in:
Nolan Lawson 2019-02-18 11:47:02 -08:00 committed by GitHub
parent ef5fb4ce0c
commit cd5b6f8e81
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 63 additions and 16 deletions

View file

@ -99,7 +99,6 @@
"terser-webpack-plugin": "^1.2.2",
"text-encoding": "^0.7.0",
"tiny-queue": "^0.2.1",
"web-animations-js": "^2.3.1",
"webpack": "^4.29.3",
"webpack-bundle-analyzer": "^3.0.4"
},

View file

@ -107,6 +107,7 @@
<script>
import { classname } from '../_utils/classname'
import { store } from '../_store/store'
import { animate } from '../_utils/animate'
export default {
data: () => ({
@ -143,8 +144,7 @@
return
}
let svg = this.refs.svg
let animations = animation.map(({ properties, options }) => svg.animate(properties, options))
animations.forEach(anim => anim.play())
animate(svg, animation)
}
}
}

View file

@ -98,4 +98,4 @@
IconButton
}
}
</script>
</script>

View file

@ -0,0 +1,59 @@
// Lightweight polyfill for web animations API element.animate()
// This is good enough for my use case, although not a full polyfill
// of the entire API
// via https://stackoverflow.com/a/15710692
function hashCode (s) {
return s.split('')
.reduce((a, b) => {
a = ((a << 5) - a) + b.charCodeAt(0)
return a & a
}, 0)
}
function generateCss (id, animations) {
let keyframes = animations.map(({ properties }, i) => (
`@keyframes keyframe-${id}-${i} {
${properties.map((obj, i) => (`${Math.round(100 * i / (properties.length - 1))}% {
${Object.keys(obj).map(key => `${key}: ${obj[key]};`).join('')}
}`
)).join('')}
}`
))
let animationCss = `.${id} {
animation: ${animations.map(({ options }, i) => {
return `keyframe-${id}-${i} ${options.duration}ms ${options.easing}`
}).join(',')};
}`
return keyframes + animationCss
}
export function animate (el, animations) {
if (typeof el.animate === 'function') {
return animations
.map(({ properties, options }) => el.animate(properties, options))
.map(anim => anim.play())
}
let hash = hashCode(JSON.stringify(animations))
let id = `anim-${hash}`
if (!document.getElementById(id)) {
let style = document.createElement('style')
style.id = id
style.textContent = generateCss(id, animations)
document.head.appendChild(style)
}
requestAnimationFrame(() => {
el.classList.add(id)
let wait = Math.max.apply(Math, animations.map(({ options }) => options.duration))
setTimeout(() => {
requestAnimationFrame(() => {
el.classList.remove(id)
})
}, wait)
})
}

View file

@ -6,10 +6,6 @@ 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'
)

View file

@ -2,15 +2,13 @@ import {
importCustomElementsPolyfill,
importIndexedDBGetAllShim,
importIntersectionObserver,
importRequestIdleCallback,
importWebAnimationPolyfill
importRequestIdleCallback
} from './asyncPolyfills'
export function loadPolyfills () {
return Promise.all([
typeof IntersectionObserver === 'undefined' && importIntersectionObserver(),
typeof requestIdleCallback === 'undefined' && importRequestIdleCallback(),
!Element.prototype.animate && importWebAnimationPolyfill(),
!IDBObjectStore.prototype.getAll && importIndexedDBGetAllShim(),
typeof customElements === 'undefined' && importCustomElementsPolyfill()
])

View file

@ -7754,11 +7754,6 @@ watchpack@^1.5.0:
graceful-fs "^4.1.2"
neo-async "^2.5.0"
web-animations-js@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/web-animations-js/-/web-animations-js-2.3.1.tgz#3a6d9bc15196377a90f8e2803fa5262165b04510"
integrity sha1-Om2bwVGWN3qQ+OKAP6UmIWWwRRA=
webauth@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/webauth/-/webauth-1.1.0.tgz#64704f6b8026986605bc3ca629952e6e26fdd100"