]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(ssr): avoid merging style generated by vShow into
authordaiwei <daiwei521@126.com>
Mon, 9 Dec 2024 13:31:46 +0000 (21:31 +0800)
committerdaiwei <daiwei521@126.com>
Mon, 9 Dec 2024 13:31:46 +0000 (21:31 +0800)
packages/compiler-ssr/__tests__/ssrVShow.spec.ts
packages/compiler-ssr/src/transforms/ssrTransformComponent.ts
packages/server-renderer/src/render.ts

index d0f3ec93036add68c9acd7181c1944407d3a5e75..fdb24521ac2791a6e8556f0e66cb92e64101cc5a 100644 (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', () => {
     expect(compileWithWrapper(`<div style="color:red" v-show="foo"/>`).code)
       .toMatchInlineSnapshot(`
index cad1ee8102897beab4c8990b99b43366c5d42655..1005ee92afd29bf934a0334bbd40d7a7356b1424 100644 (file)
@@ -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,
       )
     }
   }
index f04080b9c3127d04024b7a18cdc499118ea55af9..5ecf4985b4691453805d6bbe6f3c58aa99ff9edc 100644 (file)
@@ -92,6 +92,7 @@ export function renderComponentVNode(
   vnode: VNode,
   parentComponent: ComponentInternalInstance | null = null,
   slotScopeId?: string,
+  vShowValue?: Props | null,
 ): SSRBuffer | Promise<SSRBuffer> {
   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<SSRBuffer> {
   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) {