fix(nuxt): reuse intermediate setup state in `<ClientOnly>` (#25009)

Co-authored-by: julien huang <julien.huang@outlook.fr>
This commit is contained in:
Daniel Roe 2024-01-02 21:04:58 +00:00 committed by GitHub
parent 46148ffce7
commit 653856627c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 23 additions and 20 deletions

View File

@ -1,4 +1,4 @@
import { createElementBlock, createElementVNode, createStaticVNode, defineComponent, getCurrentInstance, h, onMounted, ref } from 'vue' import { cloneVNode, createElementBlock, createStaticVNode, defineComponent, getCurrentInstance, h, onMounted, ref } from 'vue'
import type { ComponentInternalInstance, ComponentOptions } from 'vue' import type { ComponentInternalInstance, ComponentOptions } from 'vue'
import { getFragmentHTML } from './utils' import { getFragmentHTML } from './utils'
@ -33,11 +33,11 @@ export function createClientOnly<T extends ComponentOptions> (component: T) {
if (clone.render) { if (clone.render) {
// override the component render (non script setup component) // override the component render (non script setup component)
clone.render = (ctx: any, ...args: any[]) => { clone.render = (ctx: any, cache: any, $props: any, $setup: any, $data: any, $options: any) => {
if (ctx.mounted$) { if ($setup.mounted$ ?? ctx.mounted$) {
const res = component.render?.bind(ctx)(ctx, ...args) const res = component.render?.bind(ctx)(ctx, cache, $props, $setup, $data, $options)
return (res.children === null || typeof res.children === 'string') return (res.children === null || typeof res.children === 'string')
? createElementVNode(res.type, res.props, res.children, res.patchFlag, res.dynamicProps, res.shapeFlag) ? cloneVNode(res)
: h(res) : h(res)
} else { } else {
const fragment = getFragmentHTML(ctx._.vnode.el ?? null) ?? ['<div></div>'] const fragment = getFragmentHTML(ctx._.vnode.el ?? null) ?? ['<div></div>']
@ -70,19 +70,22 @@ export function createClientOnly<T extends ComponentOptions> (component: T) {
return Promise.resolve(component.setup?.(props, ctx) || {}) return Promise.resolve(component.setup?.(props, ctx) || {})
.then((setupState) => { .then((setupState) => {
return typeof setupState !== 'function' if (typeof setupState !== 'function') {
? { ...setupState, mounted$ } setupState = setupState || {}
: (...args: any[]) => { setupState.mounted$ = mounted$
if (mounted$.value) { return setupState
const res = setupState(...args) }
return (res.children === null || typeof res.children === 'string') return (...args: any[]) => {
? createElementVNode(res.type, res.props, res.children, res.patchFlag, res.dynamicProps, res.shapeFlag) if (mounted$.value) {
: h(res) const res = setupState(...args)
} else { return (res.children === null || typeof res.children === 'string')
const fragment = getFragmentHTML(instance?.vnode.el ?? null) ?? ['<div></div>'] ? cloneVNode(res)
return import.meta.client ? createStaticVNode(fragment.join(''), fragment.length) : h('div', ctx.attrs) : h(res)
} } else {
} const fragment = getFragmentHTML(instance?.vnode.el ?? null) ?? ['<div></div>']
return import.meta.client ? createStaticVNode(fragment.join(''), fragment.length) : h('div', ctx.attrs)
}
}
}) })
} }

View File

@ -4,11 +4,11 @@ function exposedFunc () {
} }
defineExpose({ exposedFunc }) defineExpose({ exposedFunc })
const $hello = ref('hello')
await new Promise(resolve => setTimeout(resolve, 300)) await new Promise(resolve => setTimeout(resolve, 300))
onMounted(() => { onMounted(() => {
console.log('mounted') console.log('mounted', $hello.value)
}) })
</script> </script>