fix(nuxt): render client page directly when not hydrating (#30061)

This commit is contained in:
Julien Huang 2024-12-09 11:34:00 +01:00 committed by Daniel Roe
parent 3947a7b97c
commit 94e643193e
No known key found for this signature in database
GPG Key ID: 3714AB03996F442B
2 changed files with 49 additions and 6 deletions

View File

@ -1,6 +1,7 @@
import { defineAsyncComponent, defineComponent, h } from 'vue'
import type { AsyncComponentLoader } from 'vue'
import ClientOnly from '#app/components/client-only'
import { useNuxtApp } from '#app/nuxt'
/* @__NO_SIDE_EFFECTS__ */
export const createClientPage = (loader: AsyncComponentLoader) => {
@ -15,11 +16,15 @@ export const createClientPage = (loader: AsyncComponentLoader) => {
return defineComponent({
inheritAttrs: false,
setup (_, { attrs }) {
return () => h('div', [
h(ClientOnly, undefined, {
default: () => h(page, attrs),
}),
])
const nuxtApp = useNuxtApp()
if (import.meta.server || nuxtApp.isHydrating) {
return () => h('div', [
h(ClientOnly, undefined, {
default: () => h(page, attrs),
}),
])
}
return () => h(page, attrs)
},
})
}

View File

@ -1,8 +1,10 @@
import { describe, expect, it } from 'vitest'
import type { ComponentOptions } from 'vue'
import { defineComponent, h, toDisplayString, useAttrs } from 'vue'
import { Suspense, defineComponent, h, toDisplayString, useAttrs } from 'vue'
import { mountSuspended } from '@nuxt/test-utils/runtime'
import { flushPromises, mount } from '@vue/test-utils'
import { createClientOnly } from '../../packages/nuxt/src/app/components/client-only'
import { createClientPage } from '../../packages/nuxt/dist/components/runtime/client-component'
const Client = defineComponent({
name: 'TestClient',
@ -27,3 +29,39 @@ describe('createClient attribute inheritance', () => {
`)
})
})
describe('client page', () => {
it('Should be suspensed when out of hydration', async () => {
let resolve
const promise = new Promise((_resolve) => {
resolve = _resolve
})
const comp = defineComponent({
async setup () {
await promise
return () => h('div', { id: 'async' }, 'async resolved')
},
})
const wrapper = mount({
setup () {
return () => h('div', {}, [
h(Suspense, {}, {
default: () => h(createClientPage(() => Promise.resolve(comp)), {}),
fallback: () => h('div', { id: 'fallback' }, 'loading'),
}),
])
},
})
await flushPromises()
expect(wrapper.find('#fallback').exists()).toBe(true)
expect(wrapper.find('#async').exists()).toBe(false)
resolve!()
await flushPromises()
expect(wrapper.find('#async').exists()).toBe(true)
expect(wrapper.find('#fallback').exists()).toBe(false)
})
})