mirror of
https://github.com/nuxt/nuxt.git
synced 2025-02-16 21:58:19 +00:00
fix: merge attrs at render
This fixes a reactivity issue and adds an accompanying test case
This commit is contained in:
parent
70b7739739
commit
373e223268
@ -13,9 +13,8 @@ export const createLazyIOComponent = (loader: AsyncComponentLoader) => {
|
||||
},
|
||||
setup (props, { attrs }) {
|
||||
const comp = defineAsyncComponent({ loader, hydrate: hydrateOnVisible(props.hydrate as IntersectionObserverInit | undefined) })
|
||||
const merged = mergeProps(attrs, { 'data-allow-mismatch': '' })
|
||||
// TODO: fix hydration mismatches on Vue's side. The data-allow-mismatch is ideally a temporary solution due to Vue's SSR limitation with hydrated content.
|
||||
return () => h(comp, merged)
|
||||
return () => h(comp, mergeProps(attrs, { 'data-allow-mismatch': '' }))
|
||||
},
|
||||
})
|
||||
}
|
||||
@ -31,14 +30,13 @@ export const createLazyNetworkComponent = (loader: AsyncComponentLoader) => {
|
||||
},
|
||||
},
|
||||
setup (props, { attrs }) {
|
||||
const merged = mergeProps(attrs, { 'data-allow-mismatch': '' })
|
||||
if (props.hydrate === 0) {
|
||||
const comp = defineAsyncComponent(loader)
|
||||
return () => h(comp, merged)
|
||||
return () => h(comp, mergeProps(attrs, { 'data-allow-mismatch': '' }))
|
||||
}
|
||||
const comp = defineAsyncComponent({ loader, hydrate: hydrateOnIdle(props.hydrate) })
|
||||
// TODO: fix hydration mismatches on Vue's side. The data-allow-mismatch is ideally a temporary solution due to Vue's SSR limitation with hydrated content.
|
||||
return () => h(comp, merged)
|
||||
return () => h(comp, mergeProps(attrs, { 'data-allow-mismatch': '' }))
|
||||
},
|
||||
})
|
||||
}
|
||||
@ -57,9 +55,8 @@ export const createLazyEventComponent = (loader: AsyncComponentLoader) => {
|
||||
setup (props, { attrs }) {
|
||||
// @ts-expect-error Cannot type HTMLElementEventMap in props
|
||||
const comp = defineAsyncComponent({ loader, hydrate: hydrateOnInteraction(props.hydrate) })
|
||||
const merged = mergeProps(attrs, { 'data-allow-mismatch': '' })
|
||||
// TODO: fix hydration mismatches on Vue's side. The data-allow-mismatch is ideally a temporary solution due to Vue's SSR limitation with hydrated content.
|
||||
return () => h(comp, merged)
|
||||
return () => h(comp, mergeProps(attrs, { 'data-allow-mismatch': '' }))
|
||||
},
|
||||
})
|
||||
}
|
||||
@ -77,9 +74,8 @@ export const createLazyMediaComponent = (loader: AsyncComponentLoader) => {
|
||||
},
|
||||
setup (props, { attrs }) {
|
||||
const comp = defineAsyncComponent({ loader, hydrate: hydrateOnMediaQuery(props.hydrate) })
|
||||
const merged = mergeProps(attrs, { 'data-allow-mismatch': '' })
|
||||
// TODO: fix hydration mismatches on Vue's side. The data-allow-mismatch is ideally a temporary solution due to Vue's SSR limitation with hydrated content.
|
||||
return () => h(comp, merged)
|
||||
return () => h(comp, mergeProps(attrs, { 'data-allow-mismatch': '' }))
|
||||
},
|
||||
})
|
||||
}
|
||||
@ -96,18 +92,17 @@ export const createLazyIfComponent = (loader: AsyncComponentLoader) => {
|
||||
},
|
||||
},
|
||||
setup (props, { attrs }) {
|
||||
const merged = mergeProps(attrs, { 'data-allow-mismatch': '' })
|
||||
if (props.hydrate) {
|
||||
const comp = defineAsyncComponent(loader)
|
||||
// TODO: fix hydration mismatches on Vue's side. The data-allow-mismatch is ideally a temporary solution due to Vue's SSR limitation with hydrated content.
|
||||
return () => h(comp, merged)
|
||||
return () => h(comp, mergeProps(attrs, { 'data-allow-mismatch': '' }))
|
||||
}
|
||||
const strategy: HydrationStrategy = (hydrate) => {
|
||||
const unwatch = watch(() => props.hydrate, () => hydrate(), { once: true })
|
||||
return () => unwatch()
|
||||
}
|
||||
const comp = defineAsyncComponent({ loader, hydrate: strategy })
|
||||
return () => h(comp, merged)
|
||||
return () => h(comp, mergeProps(attrs, { 'data-allow-mismatch': '' }))
|
||||
},
|
||||
})
|
||||
}
|
||||
@ -124,10 +119,9 @@ export const createLazyTimeComponent = (loader: AsyncComponentLoader) => {
|
||||
},
|
||||
},
|
||||
setup (props, { attrs }) {
|
||||
const merged = mergeProps(attrs, { 'data-allow-mismatch': '' })
|
||||
if (props.hydrate === 0) {
|
||||
const comp = defineAsyncComponent(loader)
|
||||
return () => h(comp, merged)
|
||||
return () => h(comp, mergeProps(attrs, { 'data-allow-mismatch': '' }))
|
||||
}
|
||||
const strategy: HydrationStrategy = (hydrate) => {
|
||||
const id = setTimeout(hydrate, props.hydrate)
|
||||
@ -135,7 +129,7 @@ export const createLazyTimeComponent = (loader: AsyncComponentLoader) => {
|
||||
}
|
||||
const comp = defineAsyncComponent({ loader, hydrate: strategy })
|
||||
// TODO: fix hydration mismatches on Vue's side. The data-allow-mismatch is ideally a temporary solution due to Vue's SSR limitation with hydrated content.
|
||||
return () => h(comp, merged)
|
||||
return () => h(comp, mergeProps(attrs, { 'data-allow-mismatch': '' }))
|
||||
},
|
||||
})
|
||||
}
|
||||
@ -151,11 +145,10 @@ export const createLazyPromiseComponent = (loader: AsyncComponentLoader) => {
|
||||
},
|
||||
},
|
||||
setup (props, { attrs }) {
|
||||
const merged = mergeProps(attrs, { 'data-allow-mismatch': '' })
|
||||
if (!props.hydrate || typeof props.hydrate.then !== 'function') {
|
||||
const comp = defineAsyncComponent(loader)
|
||||
// TODO: fix hydration mismatches on Vue's side. The data-allow-mismatch is ideally a temporary solution due to Vue's SSR limitation with hydrated content.
|
||||
return () => h(comp, merged)
|
||||
return () => h(comp, mergeProps(attrs, { 'data-allow-mismatch': '' }))
|
||||
}
|
||||
const strategy: HydrationStrategy = (hydrate) => {
|
||||
// @ts-expect-error TS does not see hydrate as non-null
|
||||
@ -163,7 +156,7 @@ export const createLazyPromiseComponent = (loader: AsyncComponentLoader) => {
|
||||
return () => {}
|
||||
}
|
||||
const comp = defineAsyncComponent({ loader, hydrate: strategy })
|
||||
return () => h(comp, merged)
|
||||
return () => h(comp, mergeProps(attrs, { 'data-allow-mismatch': '' }))
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@ -2839,6 +2839,16 @@ describe('lazy import components', () => {
|
||||
await page.waitForTimeout(2100) // Some room for falkiness and intermittent lag
|
||||
expect(await page.locator('body').getByText('This should be visible at first with promise!').all()).toHaveLength(0)
|
||||
})
|
||||
it('keeps reactivity with models', async () => {
|
||||
const { page } = await renderPage('/lazy-import-components/model')
|
||||
expect(await page.locator('#count').textContent()).toBe('0')
|
||||
await page.locator('#count').click()
|
||||
for (let i = 0; i < 10; i++) {
|
||||
expect(await page.locator('#count').textContent()).toBe(`${i}`)
|
||||
await page.locator('#inc').click()
|
||||
}
|
||||
expect(await page.locator('#count').textContent()).toBe('10')
|
||||
})
|
||||
})
|
||||
|
||||
describe('defineNuxtComponent watch duplicate', () => {
|
||||
|
15
test/fixtures/basic/components/DelayedModel.vue
vendored
Normal file
15
test/fixtures/basic/components/DelayedModel.vue
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
<template>
|
||||
<div>
|
||||
<span id="count">{{ model }}</span>
|
||||
<button
|
||||
id="inc"
|
||||
@click="model++"
|
||||
>
|
||||
Increment
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const model = defineModel()
|
||||
</script>
|
9
test/fixtures/basic/pages/lazy-import-components/model.vue
vendored
Normal file
9
test/fixtures/basic/pages/lazy-import-components/model.vue
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
<template>
|
||||
<div>
|
||||
<LazyEventDelayedModel v-model="model" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const model = ref(0)
|
||||
</script>
|
Loading…
Reference in New Issue
Block a user