]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(ssr): render fallthrough attributes for transition-group with tag
authorEvan You <yyx990803@gmail.com>
Wed, 18 May 2022 01:55:39 +0000 (09:55 +0800)
committerEvan You <yyx990803@gmail.com>
Wed, 18 May 2022 01:55:39 +0000 (09:55 +0800)
fix #5141

packages/compiler-ssr/__tests__/ssrTransitionGroup.spec.ts
packages/compiler-ssr/src/transforms/ssrTransformComponent.ts
packages/compiler-ssr/src/transforms/ssrTransformTransitionGroup.ts

index aee771fb3fe4fd1af85bd9db02bb5a22e3dbf37f..2a3b6d3b4d488d3ac049117df97cd2408b679690 100644 (file)
@@ -26,10 +26,10 @@ describe('transition-group', () => {
         `<transition-group tag="ul"><div v-for="i in list"/></transition-group>`
       ).code
     ).toMatchInlineSnapshot(`
-      "const { ssrRenderList: _ssrRenderList } = require(\\"vue/server-renderer\\")
+      "const { ssrRenderAttrs: _ssrRenderAttrs, ssrRenderList: _ssrRenderList } = require(\\"vue/server-renderer\\")
 
       return function ssrRender(_ctx, _push, _parent, _attrs) {
-        _push(\`<ul>\`)
+        _push(\`<ul\${_ssrRenderAttrs(_attrs)}>\`)
         _ssrRenderList(_ctx.list, (i) => {
           _push(\`<div></div>\`)
         })
@@ -44,10 +44,14 @@ describe('transition-group', () => {
         `<transition-group :tag="someTag"><div v-for="i in list"/></transition-group>`
       ).code
     ).toMatchInlineSnapshot(`
-      "const { ssrRenderList: _ssrRenderList } = require(\\"vue/server-renderer\\")
+      "const { ssrRenderAttrs: _ssrRenderAttrs, ssrRenderList: _ssrRenderList } = require(\\"vue/server-renderer\\")
 
       return function ssrRender(_ctx, _push, _parent, _attrs) {
-        _push(\`<\${_ctx.someTag}>\`)
+        _push(\`<\${
+          _ctx.someTag
+        }\${
+          _ssrRenderAttrs(_attrs)
+        }>\`)
         _ssrRenderList(_ctx.list, (i) => {
           _push(\`<div></div>\`)
         })
@@ -85,4 +89,23 @@ describe('transition-group', () => {
       }"
     `)
   })
+
+  test('attribute fallthrough', () => {
+    expect(
+      compile(
+        `<transition-group tag="ul" class="red" id="ok">
+        </transition-group>`
+      ).code
+    ).toMatchInlineSnapshot(`
+      "const { mergeProps: _mergeProps } = require(\\"vue\\")
+      const { ssrRenderAttrs: _ssrRenderAttrs } = require(\\"vue/server-renderer\\")
+
+      return function ssrRender(_ctx, _push, _parent, _attrs) {
+        _push(\`<ul\${_ssrRenderAttrs(_mergeProps({
+          class: \\"red\\",
+          id: \\"ok\\"
+        }, _attrs))}></ul>\`)
+      }"
+    `)
+  })
 })
index 83d552103caf5c6de6eb83b0b93a58aa846c2845..4c3a961cd6598a11da8d6c677dc6bd844c19f2e0 100644 (file)
@@ -48,7 +48,10 @@ import {
   ssrProcessSuspense,
   ssrTransformSuspense
 } from './ssrTransformSuspense'
-import { ssrProcessTransitionGroup } from './ssrTransformTransitionGroup'
+import {
+  ssrProcessTransitionGroup,
+  ssrTransformTransitionGroup
+} from './ssrTransformTransitionGroup'
 import { isSymbol, isObject, isArray } from '@vue/shared'
 import { buildSSRProps } from './ssrTransformElement'
 
@@ -95,7 +98,10 @@ export const ssrTransformComponent: NodeTransform = (node, context) => {
     if (component === SUSPENSE) {
       return ssrTransformSuspense(node, context)
     }
-    return // built-in component: fallthrough
+    if (component === TRANSITION_GROUP) {
+      return ssrTransformTransitionGroup(node, context)
+    }
+    return // other built-in components: fallthrough
   }
 
   // Build the fallback vnode-based branch for the component's slots.
index 378c4f333d4e4cf2d3ba1318d3289d758f3958fe..dedf1f6407552262a626bdeaeaf07c6aa434804c 100644 (file)
@@ -1,16 +1,71 @@
-import { ComponentNode, findProp, NodeTypes } from '@vue/compiler-dom'
+import {
+  AttributeNode,
+  buildProps,
+  ComponentNode,
+  createCallExpression,
+  DirectiveNode,
+  findProp,
+  JSChildNode,
+  NodeTypes,
+  TransformContext
+} from '@vue/compiler-dom'
+import { SSR_RENDER_ATTRS } from '../runtimeHelpers'
 import { processChildren, SSRTransformContext } from '../ssrCodegenTransform'
+import { buildSSRProps } from './ssrTransformElement'
 
+const wipMap = new WeakMap<ComponentNode, WIPEntry>()
+
+interface WIPEntry {
+  tag: AttributeNode | DirectiveNode
+  propsExp: string | JSChildNode | null
+}
+
+// phase 1: build props
+export function ssrTransformTransitionGroup(
+  node: ComponentNode,
+  context: TransformContext
+) {
+  return () => {
+    const tag = findProp(node, 'tag')
+    if (tag) {
+      const otherProps = node.props.filter(p => p !== tag)
+      const { props, directives } = buildProps(
+        node,
+        context,
+        otherProps,
+        true, /* isComponent */
+        false, /* isDynamicComponent */
+        true /* ssr (skip event listeners) */
+      )
+      let propsExp = null
+      if (props || directives.length) {
+        propsExp = createCallExpression(context.helper(SSR_RENDER_ATTRS), [
+          buildSSRProps(props, directives, context)
+        ])
+      }
+      wipMap.set(node, {
+        tag,
+        propsExp
+      })
+    }
+  }
+}
+
+// phase 2: process children
 export function ssrProcessTransitionGroup(
   node: ComponentNode,
   context: SSRTransformContext
 ) {
-  const tag = findProp(node, 'tag')
-  if (tag) {
+  const entry = wipMap.get(node)
+  if (entry) {
+    const { tag, propsExp } = entry
     if (tag.type === NodeTypes.DIRECTIVE) {
       // dynamic :tag
       context.pushStringPart(`<`)
       context.pushStringPart(tag.exp!)
+      if (propsExp) {
+        context.pushStringPart(propsExp)
+      }
       context.pushStringPart(`>`)
 
       processChildren(
@@ -30,7 +85,11 @@ export function ssrProcessTransitionGroup(
       context.pushStringPart(`>`)
     } else {
       // static tag
-      context.pushStringPart(`<${tag.value!.content}>`)
+      context.pushStringPart(`<${tag.value!.content}`)
+      if (propsExp) {
+        context.pushStringPart(propsExp)
+      }
+      context.pushStringPart(`>`)
       processChildren(node, context, false, true)
       context.pushStringPart(`</${tag.value!.content}>`)
     }