fix: use smooth scroll polyfill in Chrome for scroll-to-top (#1601)
* fix: use smooth scroll polyfill in Chrome for scroll-to-top * rename thunk to __thunk__ for safety
This commit is contained in:
parent
0194a07823
commit
7c04b86405
|
@ -8,6 +8,7 @@ import replace from 'rollup-plugin-replace'
|
|||
import fromPairs from 'lodash-es/fromPairs'
|
||||
import babel from 'rollup-plugin-babel'
|
||||
import { themes } from '../src/routes/_static/themes'
|
||||
import terserOptions from './terserOptions'
|
||||
|
||||
const writeFile = promisify(fs.writeFile)
|
||||
|
||||
|
@ -28,11 +29,7 @@ export async function buildInlineScript () {
|
|||
runtimeHelpers: true,
|
||||
presets: ['@babel/preset-env']
|
||||
}),
|
||||
!process.env.DEBUG && terser({
|
||||
mangle: true,
|
||||
compress: true,
|
||||
ecma: 8
|
||||
})
|
||||
!process.env.DEBUG && terser(terserOptions)
|
||||
]
|
||||
})
|
||||
const { output } = await bundle.generate({
|
||||
|
|
14
bin/terserOptions.js
Normal file
14
bin/terserOptions.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
module.exports = {
|
||||
ecma: 8,
|
||||
mangle: true,
|
||||
compress: {
|
||||
pure_funcs: [
|
||||
'console.log', // remove console logs in production
|
||||
'__thunk__' // see thunk.js
|
||||
]
|
||||
},
|
||||
output: {
|
||||
comments: false
|
||||
},
|
||||
safari10: true
|
||||
}
|
|
@ -333,7 +333,7 @@
|
|||
// smooth scroll, so disable smooth scrolling
|
||||
scroller.scrollLeft = scrollLeft
|
||||
} else {
|
||||
smoothScroll(scroller, scrollLeft, true)
|
||||
smoothScroll(scroller, scrollLeft, /* horizontal */ true, /* preferFast */ false)
|
||||
}
|
||||
} else {
|
||||
console.log('setting scrollLeft', scrollLeft)
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
if (index === 0 && movement === -1) {
|
||||
activeItemKey = null
|
||||
this.set({ activeItemKey })
|
||||
smoothScroll(getScrollContainer(), 0)
|
||||
smoothScroll(getScrollContainer(), 0, /* horizontal */ false, /* preferFast */ false)
|
||||
return
|
||||
}
|
||||
if (index === -1) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import emojiRegex from 'emoji-regex/es2015/text'
|
||||
import { thunk } from './thunk'
|
||||
import { __thunk__ } from './thunk'
|
||||
|
||||
export const getEmojiRegex = thunk(emojiRegex)
|
||||
export const getEmojiRegex = __thunk__(emojiRegex)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* eslint-disable */
|
||||
import { thunk } from './thunk'
|
||||
import { __thunk__ } from './thunk'
|
||||
|
||||
export const handleRegex = thunk(() => /(^|[^\/\w])@(([a-z0-9_]+)@[a-z0-9\.\-]+[a-z0-9]+)/ig)
|
||||
export const handleRegex = __thunk__(() => /(^|[^\/\w])@(([a-z0-9_]+)@[a-z0-9\.\-]+[a-z0-9]+)/ig)
|
||||
/* eslint-enable */
|
||||
|
|
|
@ -66,5 +66,5 @@ export function scrollIntoViewIfNeeded (element) {
|
|||
}
|
||||
const scrollContainer = getScrollContainer()
|
||||
const scrollTop = scrollContainer.scrollTop
|
||||
smoothScroll(scrollContainer, scrollTop + rect.top - scrollY)
|
||||
smoothScroll(scrollContainer, scrollTop + rect.top - scrollY, /* horizontal */ false, /* preferFast */ false)
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ export function scrollToTop (smooth) {
|
|||
return false
|
||||
}
|
||||
if (smooth) {
|
||||
smoothScroll(scroller, 0)
|
||||
smoothScroll(scroller, 0, /* horizontal */ false, /* preferFast */ true)
|
||||
} else {
|
||||
scroller.scrollTop = 0
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { store } from '../_store/store'
|
||||
import { isChrome } from './userAgent'
|
||||
|
||||
// via https://github.com/tootsuite/mastodon/blob/f59ed3a4fafab776b4eeb92f805dfe1fecc17ee3/app/javascript/mastodon/scroll.js
|
||||
const easingOutQuint = (x, t, b, c, d) =>
|
||||
|
@ -63,16 +64,22 @@ function testSupportsSmoothScroll () {
|
|||
|
||||
export const hasNativeSmoothScroll = process.browser && testSupportsSmoothScroll()
|
||||
|
||||
export function smoothScroll (node, topOrLeft, horizontal) {
|
||||
export function smoothScroll (node, topOrLeft, horizontal, preferFast) {
|
||||
if (store.get().reduceMotion) {
|
||||
// don't do smooth-scroll at all for users who prefer reduced motion
|
||||
console.log('smooth scroll: disabled')
|
||||
// Don't do smooth-scroll at all for users who prefer reduced motion.
|
||||
node[horizontal ? 'scrollLeft' : 'scrollTop'] = topOrLeft
|
||||
} else if (hasNativeSmoothScroll) {
|
||||
} else if (hasNativeSmoothScroll && !(preferFast && isChrome())) {
|
||||
// In some cases (e.g. scrolling to the top of the timeline), Chrome can take a really long time
|
||||
// in their native smooth scroll implementation. If preferFast is true, just use the polyfill
|
||||
// so we can control how long it takes.
|
||||
console.log('smooth scroll: using native')
|
||||
return node.scrollTo({
|
||||
[horizontal ? 'left' : 'top']: topOrLeft,
|
||||
behavior: 'smooth'
|
||||
})
|
||||
} else {
|
||||
console.log('smooth scroll: using polyfill')
|
||||
return smoothScrollPolyfill(node, horizontal ? 'scrollLeft' : 'scrollTop', topOrLeft)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
// LocalStorage and IDB may be disabled in private mode, when "blocking cookies" in Safari,
|
||||
// or other cases
|
||||
|
||||
import { thunk } from './thunk'
|
||||
import { __thunk__ } from './thunk'
|
||||
|
||||
const testKey = '__test__'
|
||||
|
||||
export const testHasLocalStorage = thunk(() => {
|
||||
export const testHasLocalStorage = __thunk__(() => {
|
||||
try {
|
||||
localStorage.setItem(testKey, testKey)
|
||||
if (!localStorage.length || localStorage.getItem(testKey) !== testKey) {
|
||||
|
@ -18,7 +18,7 @@ export const testHasLocalStorage = thunk(() => {
|
|||
return true
|
||||
})
|
||||
|
||||
export const testHasIndexedDB = thunk(async () => {
|
||||
export const testHasIndexedDB = __thunk__(async () => {
|
||||
if (typeof indexedDB === 'undefined') {
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
export function thunk (func) {
|
||||
// We name this __thunk__ so that we can tell terser that it's a pure function, without possibly
|
||||
// affecting third-party libraries that may also be using a function called "thunk".
|
||||
export function __thunk__ (func) {
|
||||
let cached
|
||||
let runOnce
|
||||
return () => {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { thunk } from './thunk'
|
||||
import { __thunk__ } from './thunk'
|
||||
|
||||
export const urlRegex = thunk(() => {
|
||||
export const urlRegex = __thunk__(() => {
|
||||
// this is provided at build time to avoid having a lot of runtime code just to build
|
||||
// a static regex
|
||||
return process.env.URL_REGEX
|
||||
|
|
|
@ -1,19 +1,24 @@
|
|||
import { thunk } from './thunk'
|
||||
import { __thunk__ } from './thunk'
|
||||
|
||||
export const isKaiOS = thunk(() => process.browser && /KAIOS/.test(navigator.userAgent))
|
||||
export const isKaiOS = __thunk__(() => process.browser && /KAIOS/.test(navigator.userAgent))
|
||||
|
||||
export const isIOS = thunk(() => process.browser && /iP(?:hone|ad|od)/.test(navigator.userAgent))
|
||||
export const isIOS = __thunk__(() => process.browser && /iP(?:hone|ad|od)/.test(navigator.userAgent))
|
||||
|
||||
export const isMac = thunk(() => process.browser && /mac/i.test(navigator.platform))
|
||||
export const isMac = __thunk__(() => process.browser && /mac/i.test(navigator.platform))
|
||||
|
||||
// IntersectionObserver introduced in iOS 12.2 https://caniuse.com/#feat=intersectionobserver
|
||||
export const isIOSPre12Point2 = thunk(() => process.browser && isIOS() &&
|
||||
export const isIOSPre12Point2 = __thunk__(() => process.browser && isIOS() &&
|
||||
!(typeof IntersectionObserver === 'function' &&
|
||||
IntersectionObserver.toString().includes('[native code]')))
|
||||
|
||||
// PointerEvent introduced in iOS 13 https://caniuse.com/#feat=pointer
|
||||
export const isIOSPre13 = thunk(() => process.browser && isIOS() &&
|
||||
export const isIOSPre13 = __thunk__(() => process.browser && isIOS() &&
|
||||
!(typeof PointerEvent === 'function' &&
|
||||
PointerEvent.toString().includes('[native code]')))
|
||||
|
||||
export const isMobile = thunk(() => process.browser && navigator.userAgent.match(/(?:iPhone|iPod|iPad|Android|KAIOS)/))
|
||||
export const isMobile = __thunk__(() => process.browser && navigator.userAgent.match(/(?:iPhone|iPod|iPad|Android|KAIOS)/))
|
||||
|
||||
export const isSafari = __thunk__(() => process.browser && /Safari/.test(navigator.userAgent) &&
|
||||
!/Chrome/.test(navigator.userAgent))
|
||||
|
||||
export const isChrome = __thunk__(() => process.browser && /Chrome/.test(navigator.userAgent))
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
import { decode as decodeBlurHash } from 'blurhash'
|
||||
import registerPromiseWorker from 'promise-worker/register'
|
||||
import { BLURHASH_RESOLUTION as RESOLUTION } from '../_static/blurhash'
|
||||
|
||||
const isChrome = /Chrome/.test(navigator.userAgent)
|
||||
import { isChrome } from '../_utils/userAgent'
|
||||
|
||||
// Disabled in Chrome because convertToBlob() is slow
|
||||
// https://github.com/nolanlawson/pinafore/issues/1396
|
||||
const OFFSCREEN_CANVAS = !isChrome && typeof OffscreenCanvas === 'function'
|
||||
const OFFSCREEN_CANVAS = !isChrome() && typeof OffscreenCanvas === 'function'
|
||||
? new OffscreenCanvas(RESOLUTION, RESOLUTION) : null
|
||||
const OFFSCREEN_CANVAS_CONTEXT_2D = OFFSCREEN_CANVAS
|
||||
? OFFSCREEN_CANVAS.getContext('2d') : null
|
||||
|
|
|
@ -3,11 +3,8 @@ import {
|
|||
shell as __shell__,
|
||||
routes as __routes__
|
||||
} from '../__sapper__/service-worker.js'
|
||||
|
||||
import {
|
||||
get,
|
||||
post
|
||||
} from './routes/_utils/ajax'
|
||||
import { get, post } from './routes/_utils/ajax'
|
||||
import { isSafari } from './routes/_utils/userAgent'
|
||||
|
||||
const timestamp = process.env.SAPPER_TIMESTAMP
|
||||
const ASSETS = `assets_${timestamp}`
|
||||
|
@ -24,8 +21,6 @@ const ON_DEMAND_CACHE = [
|
|||
}
|
||||
]
|
||||
|
||||
const isSafari = /Safari/.test(navigator.userAgent) && !/Chrom/.test(navigator.userAgent)
|
||||
|
||||
// `static` is an array of everything in the `static` directory
|
||||
const assets = __assets__
|
||||
.map(file => file.startsWith('/') ? file : `/${file}`)
|
||||
|
@ -163,7 +158,7 @@ self.addEventListener('fetch', event => {
|
|||
// range request need to be be patched with a 206 response to satisfy
|
||||
// Safari (https://stackoverflow.com/questions/52087208)
|
||||
// Once this bug is fixed in WebKit we can remove this https://bugs.webkit.org/show_bug.cgi?id=186050
|
||||
if (isSafari && event.request.headers.get('range')) {
|
||||
if (isSafari() && event.request.headers.get('range')) {
|
||||
return returnRangeRequest(req)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,19 +1,10 @@
|
|||
const TerserWebpackPlugin = require('terser-webpack-plugin')
|
||||
const terserOptions = require('../bin/terserOptions')
|
||||
|
||||
module.exports = () => new TerserWebpackPlugin({
|
||||
exclude: /(tesseract-asset|page-lifecycle)/, // tesseract causes problems, page-lifecycle is pre-minified
|
||||
cache: !process.env.TERSER_DISABLE_CACHE,
|
||||
parallel: true,
|
||||
sourceMap: true,
|
||||
terserOptions: {
|
||||
ecma: 8,
|
||||
mangle: true,
|
||||
compress: {
|
||||
pure_funcs: ['console.log']
|
||||
},
|
||||
output: {
|
||||
comments: false
|
||||
},
|
||||
safari10: true
|
||||
}
|
||||
terserOptions
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue