From 059b3cbd1791c73254643e6380390a414c199bc8 Mon Sep 17 00:00:00 2001 From: daiwei Date: Mon, 9 Dec 2024 21:31:46 +0800 Subject: [PATCH 1/4] fix(ssr): avoid merging style generated by vShow into --- .../compiler-ssr/__tests__/ssrVShow.spec.ts | 38 +++++++++++++++++ .../src/transforms/ssrTransformComponent.ts | 41 ++++++++++++++----- packages/server-renderer/src/render.ts | 18 ++++++-- 3 files changed, 84 insertions(+), 13 deletions(-) diff --git a/packages/compiler-ssr/__tests__/ssrVShow.spec.ts b/packages/compiler-ssr/__tests__/ssrVShow.spec.ts index d0f3ec93036..fdb24521ac2 100644 --- a/packages/compiler-ssr/__tests__/ssrVShow.spec.ts +++ b/packages/compiler-ssr/__tests__/ssrVShow.spec.ts @@ -33,6 +33,44 @@ describe('ssr: v-show', () => { `) }) + test('with component', () => { + expect( + compileWithWrapper(``).code, + ).toMatchInlineSnapshot(` + "const { resolveComponent: _resolveComponent } = require("vue") + const { ssrRenderComponent: _ssrRenderComponent, ssrRenderAttrs: _ssrRenderAttrs } = require("vue/server-renderer") + + return function ssrRender(_ctx, _push, _parent, _attrs) { + const _component_Foo = _resolveComponent("Foo") + + _push(\`\`) + _push(_ssrRenderComponent(_component_Foo, { style: {color:'red'} }, null, _parent, '', { + style: (_ctx.foo) ? null : { display: "none" } + })) + _push(\`\`) + }" + `) + }) + + test('with dynamic component', () => { + expect( + compileWithWrapper( + ``, + ).code, + ).toMatchInlineSnapshot(` + "const { resolveDynamicComponent: _resolveDynamicComponent, createVNode: _createVNode } = require("vue") + const { ssrRenderVNode: _ssrRenderVNode, ssrRenderAttrs: _ssrRenderAttrs } = require("vue/server-renderer") + + return function ssrRender(_ctx, _push, _parent, _attrs) { + _push(\`\`) + _ssrRenderVNode(_push, _createVNode(_resolveDynamicComponent("Foo"), { style: {color:'red'} }, null), _parent, '', { + style: (_ctx.foo) ? null : { display: "none" } + }) + _push(\`\`) + }" + `) + }) + test('with static style', () => { expect(compileWithWrapper(`
`).code) .toMatchInlineSnapshot(` diff --git a/packages/compiler-ssr/src/transforms/ssrTransformComponent.ts b/packages/compiler-ssr/src/transforms/ssrTransformComponent.ts index cad1ee81028..1005ee92afd 100644 --- a/packages/compiler-ssr/src/transforms/ssrTransformComponent.ts +++ b/packages/compiler-ssr/src/transforms/ssrTransformComponent.ts @@ -30,6 +30,7 @@ import { createCallExpression, createFunctionExpression, createIfStatement, + createObjectExpression, createReturnStatement, createRoot, createSimpleExpression, @@ -134,6 +135,17 @@ export const ssrTransformComponent: NodeTransform = (node, context) => { }) } + let vShowExp + const vShowDir = node.props.find( + p => p.type === NodeTypes.DIRECTIVE && p.name === 'show', + ) as DirectiveNode | undefined + if (vShowDir) { + node.props = node.props.filter(p => p !== vShowDir) + const directiveTransform = context.directiveTransforms['show'] + const { props } = directiveTransform!(vShowDir, node, context) + vShowExp = createObjectExpression(props) + } + let propsExp: string | JSChildNode = `null` if (node.props.length) { // note we are not passing ssr: true here because for components, v-on @@ -180,22 +192,31 @@ export const ssrTransformComponent: NodeTransform = (node, context) => { // dynamic component that resolved to a `resolveDynamicComponent` call // expression - since the resolved result may be a plain element (string) // or a VNode, handle it with `renderVNode`. + const args: (string | JSChildNode)[] = [ + `_push`, + createCallExpression(context.helper(CREATE_VNODE), [ + component, + propsExp, + slots, + ]), + `_parent`, + ] + if (vShowExp) args.push(`''`, vShowExp) node.ssrCodegenNode = createCallExpression( context.helper(SSR_RENDER_VNODE), - [ - `_push`, - createCallExpression(context.helper(CREATE_VNODE), [ - component, - propsExp, - slots, - ]), - `_parent`, - ], + args, ) } else { + const args: (string | JSChildNode)[] = [ + component, + propsExp, + slots, + `_parent`, + ] + if (vShowExp) args.push(`''`, vShowExp) node.ssrCodegenNode = createCallExpression( context.helper(SSR_RENDER_COMPONENT), - [component, propsExp, slots, `_parent`], + args, ) } } diff --git a/packages/server-renderer/src/render.ts b/packages/server-renderer/src/render.ts index f04080b9c31..5ecf4985b46 100644 --- a/packages/server-renderer/src/render.ts +++ b/packages/server-renderer/src/render.ts @@ -92,6 +92,7 @@ export function renderComponentVNode( vnode: VNode, parentComponent: ComponentInternalInstance | null = null, slotScopeId?: string, + vShowValue?: Props | null, ): SSRBuffer | Promise { const instance = (vnode.component = createComponentInstance( vnode, @@ -116,15 +117,18 @@ export function renderComponentVNode( }) // Note: error display is already done by the wrapped lifecycle hook function. .catch(NOOP) - return p.then(() => renderComponentSubTree(instance, slotScopeId)) + return p.then(() => + renderComponentSubTree(instance, slotScopeId, vShowValue), + ) } else { - return renderComponentSubTree(instance, slotScopeId) + return renderComponentSubTree(instance, slotScopeId, vShowValue) } } function renderComponentSubTree( instance: ComponentInternalInstance, slotScopeId?: string, + vShowValue?: Props | null, ): SSRBuffer | Promise { if (__DEV__) pushWarningContext(instance.vnode) const comp = instance.type as Component @@ -186,6 +190,11 @@ function renderComponentSubTree( } } + if (vShowValue) { + if (attrs) attrs = mergeProps(attrs, vShowValue) + else attrs = vShowValue + } + // set current rendering instance for asset resolution const prev = setCurrentRenderingInstance(instance) try { @@ -225,6 +234,7 @@ export function renderVNode( vnode: VNode, parentComponent: ComponentInternalInstance, slotScopeId?: string, + vShowValue?: Props | null, ): void { const { type, shapeFlag, children, dirs, props } = vnode if (dirs) { @@ -263,7 +273,9 @@ export function renderVNode( if (shapeFlag & ShapeFlags.ELEMENT) { renderElementVNode(push, vnode, parentComponent, slotScopeId) } else if (shapeFlag & ShapeFlags.COMPONENT) { - push(renderComponentVNode(vnode, parentComponent, slotScopeId)) + push( + renderComponentVNode(vnode, parentComponent, slotScopeId, vShowValue), + ) } else if (shapeFlag & ShapeFlags.TELEPORT) { renderTeleportVNode(push, vnode, parentComponent, slotScopeId) } else if (shapeFlag & ShapeFlags.SUSPENSE) { From 637409af75d52fe9d11dc17952667523b62c1132 Mon Sep 17 00:00:00 2001 From: daiwei Date: Mon, 9 Dec 2024 21:37:58 +0800 Subject: [PATCH 2/4] chore: add comment --- packages/server-renderer/src/render.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/server-renderer/src/render.ts b/packages/server-renderer/src/render.ts index 5ecf4985b46..e34072e2422 100644 --- a/packages/server-renderer/src/render.ts +++ b/packages/server-renderer/src/render.ts @@ -191,6 +191,7 @@ function renderComponentSubTree( } if (vShowValue) { + // v-show has higher priority if (attrs) attrs = mergeProps(attrs, vShowValue) else attrs = vShowValue } From 21454ce6270e87e165f7a9b3f94cf7f11a0f288f Mon Sep 17 00:00:00 2001 From: daiwei Date: Tue, 10 Dec 2024 09:02:28 +0800 Subject: [PATCH 3/4] test: add test case --- .../__tests__/ssrDirectives.spec.ts | 32 +++++++++++++++++++ .../src/helpers/ssrRenderComponent.ts | 2 ++ packages/server-renderer/src/render.ts | 6 ++-- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/packages/server-renderer/__tests__/ssrDirectives.spec.ts b/packages/server-renderer/__tests__/ssrDirectives.spec.ts index dfdebe971f5..f0a947f49bd 100644 --- a/packages/server-renderer/__tests__/ssrDirectives.spec.ts +++ b/packages/server-renderer/__tests__/ssrDirectives.spec.ts @@ -66,6 +66,38 @@ describe('ssr: directives', () => { ), ).toBe(`
`) }) + + test('with component', async () => { + expect( + await renderToString( + createApp({ + components: { + Foo: { + template: `
`, + }, + }, + data: () => ({ show: false }), + template: ``, + }), + ), + ).toBe(`
`) + }) + + test('with dynamic component', async () => { + expect( + await renderToString( + createApp({ + components: { + Foo: { + template: `
`, + }, + }, + data: () => ({ show: false }), + template: ``, + }), + ), + ).toBe(`
`) + }) }) describe('template v-model', () => { diff --git a/packages/server-renderer/src/helpers/ssrRenderComponent.ts b/packages/server-renderer/src/helpers/ssrRenderComponent.ts index 4277bb1747e..94ec2d50f77 100644 --- a/packages/server-renderer/src/helpers/ssrRenderComponent.ts +++ b/packages/server-renderer/src/helpers/ssrRenderComponent.ts @@ -13,10 +13,12 @@ export function ssrRenderComponent( children: Slots | SSRSlots | null = null, parentComponent: ComponentInternalInstance | null = null, slotScopeId?: string, + vShowValue?: Props, ): SSRBuffer | Promise { return renderComponentVNode( createVNode(comp, props, children), parentComponent, slotScopeId, + vShowValue, ) } diff --git a/packages/server-renderer/src/render.ts b/packages/server-renderer/src/render.ts index e34072e2422..af95a2fbc6e 100644 --- a/packages/server-renderer/src/render.ts +++ b/packages/server-renderer/src/render.ts @@ -92,7 +92,7 @@ export function renderComponentVNode( vnode: VNode, parentComponent: ComponentInternalInstance | null = null, slotScopeId?: string, - vShowValue?: Props | null, + vShowValue?: Props, ): SSRBuffer | Promise { const instance = (vnode.component = createComponentInstance( vnode, @@ -128,7 +128,7 @@ export function renderComponentVNode( function renderComponentSubTree( instance: ComponentInternalInstance, slotScopeId?: string, - vShowValue?: Props | null, + vShowValue?: Props, ): SSRBuffer | Promise { if (__DEV__) pushWarningContext(instance.vnode) const comp = instance.type as Component @@ -235,7 +235,7 @@ export function renderVNode( vnode: VNode, parentComponent: ComponentInternalInstance, slotScopeId?: string, - vShowValue?: Props | null, + vShowValue?: Props, ): void { const { type, shapeFlag, children, dirs, props } = vnode if (dirs) { From 4d7a6977344f0d11f4d9fc3e0f1979c6b6ff02e7 Mon Sep 17 00:00:00 2001 From: daiwei Date: Tue, 10 Dec 2024 14:00:23 +0800 Subject: [PATCH 4/4] chore: pass undefined to slotScopeId --- .../compiler-ssr/__tests__/ssrVShow.spec.ts | 42 +++++++++---------- .../src/transforms/ssrTransformComponent.ts | 4 +- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/packages/compiler-ssr/__tests__/ssrVShow.spec.ts b/packages/compiler-ssr/__tests__/ssrVShow.spec.ts index fdb24521ac2..bf8fd6090a2 100644 --- a/packages/compiler-ssr/__tests__/ssrVShow.spec.ts +++ b/packages/compiler-ssr/__tests__/ssrVShow.spec.ts @@ -37,19 +37,19 @@ describe('ssr: v-show', () => { expect( compileWithWrapper(``).code, ).toMatchInlineSnapshot(` - "const { resolveComponent: _resolveComponent } = require("vue") - const { ssrRenderComponent: _ssrRenderComponent, ssrRenderAttrs: _ssrRenderAttrs } = require("vue/server-renderer") + "const { resolveComponent: _resolveComponent } = require("vue") + const { ssrRenderComponent: _ssrRenderComponent, ssrRenderAttrs: _ssrRenderAttrs } = require("vue/server-renderer") - return function ssrRender(_ctx, _push, _parent, _attrs) { - const _component_Foo = _resolveComponent("Foo") + return function ssrRender(_ctx, _push, _parent, _attrs) { + const _component_Foo = _resolveComponent("Foo") - _push(\`\`) - _push(_ssrRenderComponent(_component_Foo, { style: {color:'red'} }, null, _parent, '', { - style: (_ctx.foo) ? null : { display: "none" } - })) - _push(\`
\`) - }" - `) + _push(\`\`) + _push(_ssrRenderComponent(_component_Foo, { style: {color:'red'} }, null, _parent, undefined, { + style: (_ctx.foo) ? null : { display: "none" } + })) + _push(\`\`) + }" + `) }) test('with dynamic component', () => { @@ -58,17 +58,17 @@ describe('ssr: v-show', () => { ``, ).code, ).toMatchInlineSnapshot(` - "const { resolveDynamicComponent: _resolveDynamicComponent, createVNode: _createVNode } = require("vue") - const { ssrRenderVNode: _ssrRenderVNode, ssrRenderAttrs: _ssrRenderAttrs } = require("vue/server-renderer") + "const { resolveDynamicComponent: _resolveDynamicComponent, createVNode: _createVNode } = require("vue") + const { ssrRenderVNode: _ssrRenderVNode, ssrRenderAttrs: _ssrRenderAttrs } = require("vue/server-renderer") - return function ssrRender(_ctx, _push, _parent, _attrs) { - _push(\`\`) - _ssrRenderVNode(_push, _createVNode(_resolveDynamicComponent("Foo"), { style: {color:'red'} }, null), _parent, '', { - style: (_ctx.foo) ? null : { display: "none" } - }) - _push(\`\`) - }" - `) + return function ssrRender(_ctx, _push, _parent, _attrs) { + _push(\`\`) + _ssrRenderVNode(_push, _createVNode(_resolveDynamicComponent("Foo"), { style: {color:'red'} }, null), _parent, undefined, { + style: (_ctx.foo) ? null : { display: "none" } + }) + _push(\`\`) + }" + `) }) test('with static style', () => { diff --git a/packages/compiler-ssr/src/transforms/ssrTransformComponent.ts b/packages/compiler-ssr/src/transforms/ssrTransformComponent.ts index 1005ee92afd..6b730088e06 100644 --- a/packages/compiler-ssr/src/transforms/ssrTransformComponent.ts +++ b/packages/compiler-ssr/src/transforms/ssrTransformComponent.ts @@ -201,7 +201,7 @@ export const ssrTransformComponent: NodeTransform = (node, context) => { ]), `_parent`, ] - if (vShowExp) args.push(`''`, vShowExp) + if (vShowExp) args.push(`undefined`, vShowExp) node.ssrCodegenNode = createCallExpression( context.helper(SSR_RENDER_VNODE), args, @@ -213,7 +213,7 @@ export const ssrTransformComponent: NodeTransform = (node, context) => { slots, `_parent`, ] - if (vShowExp) args.push(`''`, vShowExp) + if (vShowExp) args.push(`undefined`, vShowExp) node.ssrCodegenNode = createCallExpression( context.helper(SSR_RENDER_COMPONENT), args,