From cd5b6f8e810c07715f0be9f750b1681097aee81a Mon Sep 17 00:00:00 2001 From: Nolan Lawson Date: Mon, 18 Feb 2019 11:47:02 -0800 Subject: [PATCH] perf: use lite web animations polyfill (#1011) --- package.json | 1 - src/routes/_components/IconButton.html | 4 +- .../profile/AccountProfileFollow.html | 2 +- src/routes/_utils/animate.js | 59 +++++++++++++++++++ src/routes/_utils/asyncPolyfills.js | 4 -- src/routes/_utils/loadPolyfills.js | 4 +- yarn.lock | 5 -- 7 files changed, 63 insertions(+), 16 deletions(-) create mode 100644 src/routes/_utils/animate.js diff --git a/package.json b/package.json index aa494a1..be16cdb 100644 --- a/package.json +++ b/package.json @@ -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" }, diff --git a/src/routes/_components/IconButton.html b/src/routes/_components/IconButton.html index ea9257b..b48e8e7 100644 --- a/src/routes/_components/IconButton.html +++ b/src/routes/_components/IconButton.html @@ -107,6 +107,7 @@ \ No newline at end of file + diff --git a/src/routes/_utils/animate.js b/src/routes/_utils/animate.js new file mode 100644 index 0000000..3792d47 --- /dev/null +++ b/src/routes/_utils/animate.js @@ -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) + }) +} diff --git a/src/routes/_utils/asyncPolyfills.js b/src/routes/_utils/asyncPolyfills.js index 8716947..8fd253a 100644 --- a/src/routes/_utils/asyncPolyfills.js +++ b/src/routes/_utils/asyncPolyfills.js @@ -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' ) diff --git a/src/routes/_utils/loadPolyfills.js b/src/routes/_utils/loadPolyfills.js index 81bbcaa..8c7fea5 100644 --- a/src/routes/_utils/loadPolyfills.js +++ b/src/routes/_utils/loadPolyfills.js @@ -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() ]) diff --git a/yarn.lock b/yarn.lock index f32bbe9..f0d6d27 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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"