fix(ssr): avoid merging style generated by vShow into

This commit is contained in:
daiwei 2024-12-09 21:31:46 +08:00
parent 201936f9a3
commit 059b3cbd17
3 changed files with 84 additions and 13 deletions

View File

@ -33,6 +33,44 @@ describe('ssr: v-show', () => {
`) `)
}) })
test('with component', () => {
expect(
compileWithWrapper(`<Foo :style="{color:'red'}" v-show="foo"/>`).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(\`<div\${_ssrRenderAttrs(_attrs)}>\`)
_push(_ssrRenderComponent(_component_Foo, { style: {color:'red'} }, null, _parent, '', {
style: (_ctx.foo) ? null : { display: "none" }
}))
_push(\`</div>\`)
}"
`)
})
test('with dynamic component', () => {
expect(
compileWithWrapper(
`<component is="Foo" :style="{color:'red'}" v-show="foo"/>`,
).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(\`<div\${_ssrRenderAttrs(_attrs)}>\`)
_ssrRenderVNode(_push, _createVNode(_resolveDynamicComponent("Foo"), { style: {color:'red'} }, null), _parent, '', {
style: (_ctx.foo) ? null : { display: "none" }
})
_push(\`</div>\`)
}"
`)
})
test('with static style', () => { test('with static style', () => {
expect(compileWithWrapper(`<div style="color:red" v-show="foo"/>`).code) expect(compileWithWrapper(`<div style="color:red" v-show="foo"/>`).code)
.toMatchInlineSnapshot(` .toMatchInlineSnapshot(`

View File

@ -30,6 +30,7 @@ import {
createCallExpression, createCallExpression,
createFunctionExpression, createFunctionExpression,
createIfStatement, createIfStatement,
createObjectExpression,
createReturnStatement, createReturnStatement,
createRoot, createRoot,
createSimpleExpression, 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` let propsExp: string | JSChildNode = `null`
if (node.props.length) { if (node.props.length) {
// note we are not passing ssr: true here because for components, v-on // 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 // dynamic component that resolved to a `resolveDynamicComponent` call
// expression - since the resolved result may be a plain element (string) // expression - since the resolved result may be a plain element (string)
// or a VNode, handle it with `renderVNode`. // 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( node.ssrCodegenNode = createCallExpression(
context.helper(SSR_RENDER_VNODE), context.helper(SSR_RENDER_VNODE),
[ args,
`_push`,
createCallExpression(context.helper(CREATE_VNODE), [
component,
propsExp,
slots,
]),
`_parent`,
],
) )
} else { } else {
const args: (string | JSChildNode)[] = [
component,
propsExp,
slots,
`_parent`,
]
if (vShowExp) args.push(`''`, vShowExp)
node.ssrCodegenNode = createCallExpression( node.ssrCodegenNode = createCallExpression(
context.helper(SSR_RENDER_COMPONENT), context.helper(SSR_RENDER_COMPONENT),
[component, propsExp, slots, `_parent`], args,
) )
} }
} }

View File

@ -92,6 +92,7 @@ export function renderComponentVNode(
vnode: VNode, vnode: VNode,
parentComponent: ComponentInternalInstance | null = null, parentComponent: ComponentInternalInstance | null = null,
slotScopeId?: string, slotScopeId?: string,
vShowValue?: Props | null,
): SSRBuffer | Promise<SSRBuffer> { ): SSRBuffer | Promise<SSRBuffer> {
const instance = (vnode.component = createComponentInstance( const instance = (vnode.component = createComponentInstance(
vnode, vnode,
@ -116,15 +117,18 @@ export function renderComponentVNode(
}) })
// Note: error display is already done by the wrapped lifecycle hook function. // Note: error display is already done by the wrapped lifecycle hook function.
.catch(NOOP) .catch(NOOP)
return p.then(() => renderComponentSubTree(instance, slotScopeId)) return p.then(() =>
renderComponentSubTree(instance, slotScopeId, vShowValue),
)
} else { } else {
return renderComponentSubTree(instance, slotScopeId) return renderComponentSubTree(instance, slotScopeId, vShowValue)
} }
} }
function renderComponentSubTree( function renderComponentSubTree(
instance: ComponentInternalInstance, instance: ComponentInternalInstance,
slotScopeId?: string, slotScopeId?: string,
vShowValue?: Props | null,
): SSRBuffer | Promise<SSRBuffer> { ): SSRBuffer | Promise<SSRBuffer> {
if (__DEV__) pushWarningContext(instance.vnode) if (__DEV__) pushWarningContext(instance.vnode)
const comp = instance.type as Component 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 // set current rendering instance for asset resolution
const prev = setCurrentRenderingInstance(instance) const prev = setCurrentRenderingInstance(instance)
try { try {
@ -225,6 +234,7 @@ export function renderVNode(
vnode: VNode, vnode: VNode,
parentComponent: ComponentInternalInstance, parentComponent: ComponentInternalInstance,
slotScopeId?: string, slotScopeId?: string,
vShowValue?: Props | null,
): void { ): void {
const { type, shapeFlag, children, dirs, props } = vnode const { type, shapeFlag, children, dirs, props } = vnode
if (dirs) { if (dirs) {
@ -263,7 +273,9 @@ export function renderVNode(
if (shapeFlag & ShapeFlags.ELEMENT) { if (shapeFlag & ShapeFlags.ELEMENT) {
renderElementVNode(push, vnode, parentComponent, slotScopeId) renderElementVNode(push, vnode, parentComponent, slotScopeId)
} else if (shapeFlag & ShapeFlags.COMPONENT) { } else if (shapeFlag & ShapeFlags.COMPONENT) {
push(renderComponentVNode(vnode, parentComponent, slotScopeId)) push(
renderComponentVNode(vnode, parentComponent, slotScopeId, vShowValue),
)
} else if (shapeFlag & ShapeFlags.TELEPORT) { } else if (shapeFlag & ShapeFlags.TELEPORT) {
renderTeleportVNode(push, vnode, parentComponent, slotScopeId) renderTeleportVNode(push, vnode, parentComponent, slotScopeId)
} else if (shapeFlag & ShapeFlags.SUSPENSE) { } else if (shapeFlag & ShapeFlags.SUSPENSE) {