浏览代码

fix(hydration): avoid observing non-Element node (#11954)

close #11952
linzhe 1 年之前
父节点
当前提交
7257e6a342

+ 1 - 0
packages/runtime-core/src/hydrationStrategies.ts

@@ -48,6 +48,7 @@ export const hydrateOnVisible: HydrationStrategyFactory<
     }
     }
   }, opts)
   }, opts)
   forEach(el => {
   forEach(el => {
+    if (!(el instanceof Element)) return
     if (elementIsVisibleInViewport(el)) {
     if (elementIsVisibleInViewport(el)) {
       hydrate()
       hydrate()
       ob.disconnect()
       ob.disconnect()

+ 7 - 1
packages/vue/__tests__/e2e/hydration-strat-visible.html

@@ -11,9 +11,12 @@
 <script>
 <script>
   const rootMargin = location.search.match(/rootMargin=(\d+)/)?.[1] ?? 0
   const rootMargin = location.search.match(/rootMargin=(\d+)/)?.[1] ?? 0
   const isFragment = location.search.includes('?fragment')
   const isFragment = location.search.includes('?fragment')
+  const isVIf = location.search.includes('?v-if')
   if (isFragment) {
   if (isFragment) {
     document.getElementById('app').innerHTML =
     document.getElementById('app').innerHTML =
       `<!--[--><!--[--><span>one</span><!--]--><button>0</button><span>two</span><!--]-->`
       `<!--[--><!--[--><span>one</span><!--]--><button>0</button><span>two</span><!--]-->`
+  } else if (isVIf) {
+    document.getElementById('app').innerHTML = `<!---->`
   }
   }
 
 
   window.isHydrated = false
   window.isHydrated = false
@@ -24,6 +27,7 @@
     ref,
     ref,
     onMounted,
     onMounted,
     hydrateOnVisible,
     hydrateOnVisible,
+    createCommentVNode,
   } = Vue
   } = Vue
 
 
   const Comp = {
   const Comp = {
@@ -39,7 +43,9 @@
           { onClick: () => count.value++ },
           { onClick: () => count.value++ },
           count.value,
           count.value,
         )
         )
-        if (isFragment) {
+        if (isVIf) {
+          return createCommentVNode('v-if', true)
+        } else if (isFragment) {
           return [[h('span', 'one')], button, h('span', 'two')]
           return [[h('span', 'one')], button, h('span', 'two')]
         } else {
         } else {
           return button
           return button

+ 11 - 0
packages/vue/__tests__/e2e/hydrationStrategies.spec.ts

@@ -65,6 +65,17 @@ describe('async component hydration strategies', () => {
     await assertHydrationSuccess()
     await assertHydrationSuccess()
   })
   })
 
 
+  test('visible (root v-if) should not throw error', async () => {
+    const spy = vi.fn()
+    const currentPage = page()
+    currentPage.on('pageerror', spy)
+    await goToCase('visible', '?v-if')
+    await page().waitForFunction(() => window.isRootMounted)
+    expect(await page().evaluate(() => window.isHydrated)).toBe(false)
+    expect(spy).toBeCalledTimes(0)
+    currentPage.off('pageerror', spy)
+  })
+
   test('media query', async () => {
   test('media query', async () => {
     await goToCase('media')
     await goToCase('media')
     await page().waitForFunction(() => window.isRootMounted)
     await page().waitForFunction(() => window.isRootMounted)