diff --git a/packages/runtime-core/__tests__/hydration.spec.ts b/packages/runtime-core/__tests__/hydration.spec.ts index 4a9e0fac2b6..1ff141db8ab 100644 --- a/packages/runtime-core/__tests__/hydration.spec.ts +++ b/packages/runtime-core/__tests__/hydration.spec.ts @@ -1677,6 +1677,35 @@ describe('SSR hydration', () => { expect(`mismatch`).not.toHaveBeenWarned() }) + // #13394 + test('transition appear work with empty content', async () => { + const show = ref(true) + const { vnode, container } = mountWithHydration( + ``, + function (this: any) { + return h( + Transition, + { appear: true }, + { + default: () => + show.value + ? renderSlot(this.$slots, 'default') + : createTextVNode('foo'), + }, + ) + }, + ) + + // empty slot render as a comment node + expect(container.firstChild!.nodeType).toBe(Node.COMMENT_NODE) + expect(vnode.el).toBe(container.firstChild) + expect(`mismatch`).not.toHaveBeenWarned() + + show.value = false + await nextTick() + expect(container.innerHTML).toBe('foo') + }) + test('transition appear with v-if', () => { const show = false const { vnode, container } = mountWithHydration( diff --git a/packages/server-renderer/__tests__/ssrSlot.spec.ts b/packages/server-renderer/__tests__/ssrSlot.spec.ts index 4cc7fd97ef2..214e6ee840b 100644 --- a/packages/server-renderer/__tests__/ssrSlot.spec.ts +++ b/packages/server-renderer/__tests__/ssrSlot.spec.ts @@ -111,26 +111,106 @@ describe('ssr: slot', () => { }) test('transition slot', async () => { + const ReusableTransition = { + template: ``, + } + + const ReusableTransitionWithAppear = { + template: ``, + } + expect( await renderToString( createApp({ components: { - one: { - template: ``, - }, + one: ReusableTransition, }, template: `
foo
`, }), ), ).toBe(``) + expect(await renderToString(createApp(ReusableTransition))).toBe(``) + + expect(await renderToString(createApp(ReusableTransitionWithAppear))).toBe( + ``, + ) + expect( await renderToString( createApp({ components: { - one: { - template: ``, - }, + one: ReusableTransition, + }, + template: ``, + }), + ), + ).toBe(``) + + expect( + await renderToString( + createApp({ + components: { + one: ReusableTransitionWithAppear, + }, + template: ``, + }), + ), + ).toBe(``) + + expect( + await renderToString( + createApp({ + render() { + return h(ReusableTransition, null, { + default: () => null, + }) + }, + }), + ), + ).toBe(``) + + expect( + await renderToString( + createApp({ + render() { + return h(ReusableTransitionWithAppear, null, { + default: () => null, + }) + }, + }), + ), + ).toBe(``) + + expect( + await renderToString( + createApp({ + render() { + return h(ReusableTransitionWithAppear, null, { + default: () => [], + }) + }, + }), + ), + ).toBe(``) + + expect( + await renderToString( + createApp({ + render() { + return h(ReusableTransition, null, { + default: () => [], + }) + }, + }), + ), + ).toBe(``) + + expect( + await renderToString( + createApp({ + components: { + one: ReusableTransition, }, template: `
foo
`, }), diff --git a/packages/server-renderer/src/helpers/ssrRenderSlot.ts b/packages/server-renderer/src/helpers/ssrRenderSlot.ts index 19aa4ce63b7..2f93a12de9d 100644 --- a/packages/server-renderer/src/helpers/ssrRenderSlot.ts +++ b/packages/server-renderer/src/helpers/ssrRenderSlot.ts @@ -74,6 +74,8 @@ export function ssrRenderSlotInner( ) } else if (fallbackRenderFn) { fallbackRenderFn() + } else if (transition) { + push(``) } } else { // ssr slot. @@ -110,13 +112,19 @@ export function ssrRenderSlotInner( end-- } - for (let i = start; i < end; i++) { - push(slotBuffer[i]) + if (start < end) { + for (let i = start; i < end; i++) { + push(slotBuffer[i]) + } + } else if (transition) { + push(``) } } } } else if (fallbackRenderFn) { fallbackRenderFn() + } else if (transition) { + push(``) } }