From 9daab07cdf34c45045d8d518378259d51dc02b63 Mon Sep 17 00:00:00 2001 From: nieyuyao Date: Sun, 4 Aug 2024 15:15:57 +0800 Subject: [PATCH 1/2] fix(ssrRenderSlot): ensure content is valid when rendering slot --- .../runtime-core/src/helpers/renderSlot.ts | 2 +- packages/runtime-core/src/index.ts | 2 + .../server-renderer/__tests__/ssrSlot.spec.ts | 50 +++++++++++++++++++ .../src/helpers/ssrRenderSlot.ts | 6 ++- 4 files changed, 57 insertions(+), 3 deletions(-) diff --git a/packages/runtime-core/src/helpers/renderSlot.ts b/packages/runtime-core/src/helpers/renderSlot.ts index f0b13904f08..d1f8f1d8afe 100644 --- a/packages/runtime-core/src/helpers/renderSlot.ts +++ b/packages/runtime-core/src/helpers/renderSlot.ts @@ -87,7 +87,7 @@ export function renderSlot( return rendered } -function ensureValidVNode(vnodes: VNodeArrayChildren) { +export function ensureValidVNode(vnodes: VNodeArrayChildren) { return vnodes.some(child => { if (!isVNode(child)) return true if (child.type === Comment) return false diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts index 8adbe91ee17..df7b61a6cb6 100644 --- a/packages/runtime-core/src/index.ts +++ b/packages/runtime-core/src/index.ts @@ -371,6 +371,7 @@ import { import { renderComponentRoot } from './componentRenderUtils' import { setCurrentRenderingInstance } from './componentRenderContext' import { isVNode, normalizeVNode } from './vnode' +import { ensureValidVNode } from './helpers/renderSlot' const _ssrUtils = { createComponentInstance, @@ -380,6 +381,7 @@ const _ssrUtils = { isVNode, normalizeVNode, getComponentPublicInstance, + ensureValidVNode, } /** diff --git a/packages/server-renderer/__tests__/ssrSlot.spec.ts b/packages/server-renderer/__tests__/ssrSlot.spec.ts index 7e2b2247d25..02872274ab6 100644 --- a/packages/server-renderer/__tests__/ssrSlot.spec.ts +++ b/packages/server-renderer/__tests__/ssrSlot.spec.ts @@ -153,4 +153,54 @@ describe('ssr: slot', () => { ), ).toBe(`

1

2

`) }) + + // #11326 + test('dynamic component slot', async () => { + expect( + await renderToString( + createApp({ + components: { + ButtonComp: { + template: ``, + }, + Wrap: { + template: `
`, + }, + }, + template: `
hello
`, + }), + ), + ).toBe(``) + + expect( + await renderToString( + createApp({ + components: { + ButtonComp: { + template: ``, + }, + Wrap: { + template: `
`, + }, + }, + template: `
hello
`, + }), + ), + ).toBe( + ``, + ) + + expect( + await renderToString( + createApp({ + components: { + ButtonComp: { + template: ``, + }, + }, + template: ``, + }), + ), + ).toBe(``) + }) }) diff --git a/packages/server-renderer/src/helpers/ssrRenderSlot.ts b/packages/server-renderer/src/helpers/ssrRenderSlot.ts index 2069591e024..5a94faeafbf 100644 --- a/packages/server-renderer/src/helpers/ssrRenderSlot.ts +++ b/packages/server-renderer/src/helpers/ssrRenderSlot.ts @@ -1,4 +1,4 @@ -import type { ComponentInternalInstance, Slots } from 'vue' +import { type ComponentInternalInstance, type Slots, ssrUtils } from 'vue' import { type Props, type PushFn, @@ -7,6 +7,8 @@ import { } from '../render' import { isArray } from '@vue/shared' +const { ensureValidVNode } = ssrUtils + export type SSRSlots = Record export type SSRSlot = ( props: Props, @@ -60,7 +62,7 @@ export function ssrRenderSlotInner( parentComponent, slotScopeId ? ' ' + slotScopeId : '', ) - if (isArray(ret)) { + if (isArray(ret) && ensureValidVNode(ret)) { // normal slot renderVNodeChildren(push, ret, parentComponent, slotScopeId) } else { From 7eb3b6a27ee771b4dd0e62ed09892684d033ae98 Mon Sep 17 00:00:00 2001 From: nieyuyao Date: Tue, 6 Aug 2024 18:15:03 +0800 Subject: [PATCH 2/2] fix(ssrRenderSlot): check fallbackRenderFn if slotContent is invalid --- .../server-renderer/src/helpers/ssrRenderSlot.ts | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/server-renderer/src/helpers/ssrRenderSlot.ts b/packages/server-renderer/src/helpers/ssrRenderSlot.ts index 5a94faeafbf..06c2d7bfa97 100644 --- a/packages/server-renderer/src/helpers/ssrRenderSlot.ts +++ b/packages/server-renderer/src/helpers/ssrRenderSlot.ts @@ -62,9 +62,19 @@ export function ssrRenderSlotInner( parentComponent, slotScopeId ? ' ' + slotScopeId : '', ) - if (isArray(ret) && ensureValidVNode(ret)) { - // normal slot - renderVNodeChildren(push, ret, parentComponent, slotScopeId) + if (isArray(ret)) { + const validSlotContent = ensureValidVNode(ret) + if (validSlotContent) { + // normal slot + renderVNodeChildren( + push, + validSlotContent, + parentComponent, + slotScopeId, + ) + } else if (fallbackRenderFn) { + fallbackRenderFn() + } } else { // ssr slot. // check if the slot renders all comments, in which case use the fallback