From 374967ba10543ccdf528785492f25f476d2bf65b Mon Sep 17 00:00:00 2001 From: Julien Huang Date: Mon, 9 Dec 2024 11:34:00 +0100 Subject: [PATCH] fix(nuxt): render client page directly when not hydrating (#30061) --- .../components/runtime/client-component.ts | 15 ++++--- test/nuxt/client.test.ts | 40 ++++++++++++++++++- 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/packages/nuxt/src/components/runtime/client-component.ts b/packages/nuxt/src/components/runtime/client-component.ts index cb2087c12a..22201c7f8f 100644 --- a/packages/nuxt/src/components/runtime/client-component.ts +++ b/packages/nuxt/src/components/runtime/client-component.ts @@ -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) }, }) } diff --git a/test/nuxt/client.test.ts b/test/nuxt/client.test.ts index 7c9384be6f..87d34acc44 100644 --- a/test/nuxt/client.test.ts +++ b/test/nuxt/client.test.ts @@ -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) + }) +})