This commit is contained in:
edison 2025-05-06 01:40:56 +00:00 committed by GitHub
commit a40f209e11
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 53 additions and 3 deletions

View File

@ -4,6 +4,7 @@ import {
type ComponentOptions,
type ConcreteComponent,
currentInstance,
getComponentName,
isInSSRComponentSetup,
} from './component'
import { isFunction, isObject } from '@vue/shared'
@ -121,14 +122,27 @@ export function defineAsyncComponent<
__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) {

View File

@ -15,13 +15,17 @@
} = 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)
}
},
@ -37,7 +41,9 @@
onMounted(() => {
window.isRootMounted = true
})
return () => h(AsyncComp)
const show = (window.show = ref(true))
return () => h(AsyncComp, { value: show.value })
},
}).mount('#app')
</script>

View File

@ -86,6 +86,36 @@ describe('async component hydration strategies', () => {
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)