type ComponentOptions,
type ConcreteComponent,
currentInstance,
+ getComponentName,
isInSSRComponentSetup,
} from './component'
import { isFunction, isObject } from '@vue/shared'
__asyncLoader: load,
__asyncHydrate(el, instance, hydrate) {
+ let patched = false
const doHydrate = hydrateStrategy
? () => {
- const teardown = hydrateStrategy(hydrate, cb =>
+ const performHydrate = () => {
+ // skip hydration if the component has been patched
+ if (__DEV__ && patched) {
+ warn(
+ `Skipping lazy hydration for component '${getComponentName(resolvedComp!)}': ` +
+ `it was updated before lazy hydration performed.`,
+ )
+ return
+ }
+ hydrate()
+ }
+ const teardown = hydrateStrategy(performHydrate, cb =>
forEachElement(el, cb),
)
if (teardown) {
;(instance.bum || (instance.bum = [])).push(teardown)
}
+ ;(instance.u || (instance.u = [])).push(() => (patched = true))
}
: hydrate
if (resolvedComp) {
} = Vue
const Comp = {
- setup() {
+ props: {
+ value: Boolean,
+ },
+ setup(props) {
const count = ref(0)
onMounted(() => {
console.log('hydrated')
window.isHydrated = true
})
return () => {
+ props.value
return h('button', { onClick: () => count.value++ }, count.value)
}
},
onMounted(() => {
window.isRootMounted = true
})
- return () => h(AsyncComp)
+
+ const show = (window.show = ref(true))
+ return () => h(AsyncComp, { value: show.value })
},
}).mount('#app')
</script>
await assertHydrationSuccess()
})
+ // #13255
+ test('media query (patched before hydration)', async () => {
+ const spy = vi.fn()
+ const currentPage = page()
+ currentPage.on('pageerror', spy)
+
+ const warn: any[] = []
+ currentPage.on('console', e => warn.push(e.text()))
+
+ await goToCase('media')
+ await page().waitForFunction(() => window.isRootMounted)
+ expect(await page().evaluate(() => window.isHydrated)).toBe(false)
+
+ // patch
+ await page().evaluate(() => (window.show.value = false))
+ await click('button')
+ expect(await text('button')).toBe('1')
+
+ // resize
+ await page().setViewport({ width: 400, height: 600 })
+ await page().waitForFunction(() => window.isHydrated)
+ await assertHydrationSuccess('2')
+
+ expect(spy).toBeCalledTimes(0)
+ currentPage.off('pageerror', spy)
+ expect(
+ warn.some(w => w.includes('Skipping lazy hydration for component')),
+ ).toBe(true)
+ })
+
test('interaction', async () => {
await goToCase('interaction')
await page().waitForFunction(() => window.isRootMounted)