fix(nuxt): preserve instance.attrs in client-only components (#25381)

This commit is contained in:
Julien Huang 2024-01-23 11:22:45 +01:00 committed by GitHub
parent 95a5213766
commit 48ce560901
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 35 additions and 3 deletions

View File

@ -55,15 +55,18 @@ export function createClientOnly<T extends ComponentOptions> (component: T) {
clone.setup = (props, ctx) => { clone.setup = (props, ctx) => {
const instance = getCurrentInstance()! const instance = getCurrentInstance()!
const attrs = instance.attrs const attrs = { ...instance.attrs }
// remove existing directives during hydration // remove existing directives during hydration
const directives = extractDirectives(instance) const directives = extractDirectives(instance)
// prevent attrs inheritance since a staticVNode is rendered before hydration // prevent attrs inheritance since a staticVNode is rendered before hydration
instance.attrs = {} for(const key in attrs) {
delete instance.attrs[key]
}
const mounted$ = ref(false) const mounted$ = ref(false)
onMounted(() => { onMounted(() => {
instance.attrs = attrs Object.assign(instance.attrs, attrs)
instance.vnode.dirs = directives instance.vnode.dirs = directives
mounted$.value = true mounted$.value = true
}) })

29
test/nuxt/client.test.ts Normal file
View File

@ -0,0 +1,29 @@
import { describe, expect, it } from 'vitest'
import type { ComponentOptions } from 'vue'
import { defineComponent, h, toDisplayString, useAttrs } from 'vue'
import { mountSuspended } from '@nuxt/test-utils/runtime'
import { createClientOnly } from '../../packages/nuxt/src/app/components/client-only'
const Client = defineComponent({
name: 'TestClient',
setup () {
const attrs = useAttrs()
return () => h('div', {}, toDisplayString(attrs))
}
})
describe('createClient attribute inheritance', () => {
it('should retrieve attributes with useAttrs()', async () => {
const wrapper = await mountSuspended(createClientOnly(Client as ComponentOptions), {
attrs: {
id: 'client'
}
})
expect(wrapper.html()).toMatchInlineSnapshot(`
"<div id="client">{
"id": "client"
}</div>"
`)
})
})