From: Yuyao Nie Date: Wed, 7 Aug 2024 03:56:00 +0000 (+0800) Subject: fix(ssr): ensure content is valid when rendering normal slot (#11491) X-Git-Tag: v3.4.37~16 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6c903248703e2413c6197b9ad4d535f31c8eac39;p=thirdparty%2Fvuejs%2Fcore.git fix(ssr): ensure content is valid when rendering normal slot (#11491) fix #11326 --- diff --git a/packages/runtime-core/src/helpers/renderSlot.ts b/packages/runtime-core/src/helpers/renderSlot.ts index f0b13904f0..d1f8f1d8af 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 8adbe91ee1..df7b61a6cb 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 7e2b2247d2..02872274ab 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 2069591e02..06c2d7bfa9 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, @@ -61,8 +63,18 @@ export function ssrRenderSlotInner( slotScopeId ? ' ' + slotScopeId : '', ) if (isArray(ret)) { - // normal slot - renderVNodeChildren(push, ret, parentComponent, slotScopeId) + 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