]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
perf(hydration): avoid observer if element is in viewport (#11639)
authorMichael Brevard <yonshi29@gmail.com>
Wed, 18 Sep 2024 07:44:23 +0000 (10:44 +0300)
committerEvan You <evan@vuejs.org>
Wed, 18 Sep 2024 07:45:31 +0000 (15:45 +0800)
packages/runtime-core/src/hydrationStrategies.ts

index 51200fc1c34857b4b2cd3a81e1c001e02c4b0120..791ca9e5254355b5748d64d283abb6a090252ab5 100644 (file)
@@ -26,6 +26,16 @@ export const hydrateOnIdle: HydrationStrategyFactory<number> =
     return () => cancelIdleCallback(id)
   }
 
+function elementIsVisibleInViewport(el: Element) {
+  const { top, left, bottom, right } = el.getBoundingClientRect()
+  // eslint-disable-next-line no-restricted-globals
+  const { innerHeight, innerWidth } = window
+  return (
+    ((top > 0 && top < innerHeight) || (bottom > 0 && bottom < innerHeight)) &&
+    ((left > 0 && left < innerWidth) || (right > 0 && right < innerWidth))
+  )
+}
+
 export const hydrateOnVisible: HydrationStrategyFactory<
   IntersectionObserverInit
 > = opts => (hydrate, forEach) => {
@@ -37,7 +47,14 @@ export const hydrateOnVisible: HydrationStrategyFactory<
       break
     }
   }, opts)
-  forEach(el => ob.observe(el))
+  forEach(el => {
+    if (elementIsVisibleInViewport(el)) {
+      hydrate()
+      ob.disconnect()
+      return false
+    }
+    ob.observe(el)
+  })
   return () => ob.disconnect()
 }
 
@@ -85,14 +102,20 @@ export const hydrateOnInteraction: HydrationStrategyFactory<
     return teardown
   }
 
-export function forEachElement(node: Node, cb: (el: Element) => void): void {
+export function forEachElement(
+  node: Node,
+  cb: (el: Element) => void | false,
+): void {
   // fragment
   if (isComment(node) && node.data === '[') {
     let depth = 1
     let next = node.nextSibling
     while (next) {
       if (next.nodeType === DOMNodeTypes.ELEMENT) {
-        cb(next as Element)
+        const result = cb(next as Element)
+        if (result === false) {
+          break
+        }
       } else if (isComment(next)) {
         if (next.data === ']') {
           if (--depth === 0) break