Skip to content

Commit aed10c5

Browse files
committed
fix(ssr): render fallthrough attributes for transition-group with tag
fix #5141
1 parent 1035c6b commit aed10c5

File tree

3 files changed

+98
-10
lines changed

3 files changed

+98
-10
lines changed

packages/compiler-ssr/__tests__/ssrTransitionGroup.spec.ts

+27-4
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ describe('transition-group', () => {
2626
`<transition-group tag="ul"><div v-for="i in list"/></transition-group>`
2727
).code
2828
).toMatchInlineSnapshot(`
29-
"const { ssrRenderList: _ssrRenderList } = require(\\"vue/server-renderer\\")
29+
"const { ssrRenderAttrs: _ssrRenderAttrs, ssrRenderList: _ssrRenderList } = require(\\"vue/server-renderer\\")
3030
3131
return function ssrRender(_ctx, _push, _parent, _attrs) {
32-
_push(\`<ul>\`)
32+
_push(\`<ul\${_ssrRenderAttrs(_attrs)}>\`)
3333
_ssrRenderList(_ctx.list, (i) => {
3434
_push(\`<div></div>\`)
3535
})
@@ -44,10 +44,14 @@ describe('transition-group', () => {
4444
`<transition-group :tag="someTag"><div v-for="i in list"/></transition-group>`
4545
).code
4646
).toMatchInlineSnapshot(`
47-
"const { ssrRenderList: _ssrRenderList } = require(\\"vue/server-renderer\\")
47+
"const { ssrRenderAttrs: _ssrRenderAttrs, ssrRenderList: _ssrRenderList } = require(\\"vue/server-renderer\\")
4848
4949
return function ssrRender(_ctx, _push, _parent, _attrs) {
50-
_push(\`<\${_ctx.someTag}>\`)
50+
_push(\`<\${
51+
_ctx.someTag
52+
}\${
53+
_ssrRenderAttrs(_attrs)
54+
}>\`)
5155
_ssrRenderList(_ctx.list, (i) => {
5256
_push(\`<div></div>\`)
5357
})
@@ -85,4 +89,23 @@ describe('transition-group', () => {
8589
}"
8690
`)
8791
})
92+
93+
test('attribute fallthrough', () => {
94+
expect(
95+
compile(
96+
`<transition-group tag="ul" class="red" id="ok">
97+
</transition-group>`
98+
).code
99+
).toMatchInlineSnapshot(`
100+
"const { mergeProps: _mergeProps } = require(\\"vue\\")
101+
const { ssrRenderAttrs: _ssrRenderAttrs } = require(\\"vue/server-renderer\\")
102+
103+
return function ssrRender(_ctx, _push, _parent, _attrs) {
104+
_push(\`<ul\${_ssrRenderAttrs(_mergeProps({
105+
class: \\"red\\",
106+
id: \\"ok\\"
107+
}, _attrs))}></ul>\`)
108+
}"
109+
`)
110+
})
88111
})

packages/compiler-ssr/src/transforms/ssrTransformComponent.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,10 @@ import {
4848
ssrProcessSuspense,
4949
ssrTransformSuspense
5050
} from './ssrTransformSuspense'
51-
import { ssrProcessTransitionGroup } from './ssrTransformTransitionGroup'
51+
import {
52+
ssrProcessTransitionGroup,
53+
ssrTransformTransitionGroup
54+
} from './ssrTransformTransitionGroup'
5255
import { isSymbol, isObject, isArray } from '@vue/shared'
5356
import { buildSSRProps } from './ssrTransformElement'
5457

@@ -95,7 +98,10 @@ export const ssrTransformComponent: NodeTransform = (node, context) => {
9598
if (component === SUSPENSE) {
9699
return ssrTransformSuspense(node, context)
97100
}
98-
return // built-in component: fallthrough
101+
if (component === TRANSITION_GROUP) {
102+
return ssrTransformTransitionGroup(node, context)
103+
}
104+
return // other built-in components: fallthrough
99105
}
100106

101107
// Build the fallback vnode-based branch for the component's slots.

packages/compiler-ssr/src/transforms/ssrTransformTransitionGroup.ts

+63-4
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,71 @@
1-
import { ComponentNode, findProp, NodeTypes } from '@vue/compiler-dom'
1+
import {
2+
AttributeNode,
3+
buildProps,
4+
ComponentNode,
5+
createCallExpression,
6+
DirectiveNode,
7+
findProp,
8+
JSChildNode,
9+
NodeTypes,
10+
TransformContext
11+
} from '@vue/compiler-dom'
12+
import { SSR_RENDER_ATTRS } from '../runtimeHelpers'
213
import { processChildren, SSRTransformContext } from '../ssrCodegenTransform'
14+
import { buildSSRProps } from './ssrTransformElement'
315

16+
const wipMap = new WeakMap<ComponentNode, WIPEntry>()
17+
18+
interface WIPEntry {
19+
tag: AttributeNode | DirectiveNode
20+
propsExp: string | JSChildNode | null
21+
}
22+
23+
// phase 1: build props
24+
export function ssrTransformTransitionGroup(
25+
node: ComponentNode,
26+
context: TransformContext
27+
) {
28+
return () => {
29+
const tag = findProp(node, 'tag')
30+
if (tag) {
31+
const otherProps = node.props.filter(p => p !== tag)
32+
const { props, directives } = buildProps(
33+
node,
34+
context,
35+
otherProps,
36+
true, /* isComponent */
37+
false, /* isDynamicComponent */
38+
true /* ssr (skip event listeners) */
39+
)
40+
let propsExp = null
41+
if (props || directives.length) {
42+
propsExp = createCallExpression(context.helper(SSR_RENDER_ATTRS), [
43+
buildSSRProps(props, directives, context)
44+
])
45+
}
46+
wipMap.set(node, {
47+
tag,
48+
propsExp
49+
})
50+
}
51+
}
52+
}
53+
54+
// phase 2: process children
455
export function ssrProcessTransitionGroup(
556
node: ComponentNode,
657
context: SSRTransformContext
758
) {
8-
const tag = findProp(node, 'tag')
9-
if (tag) {
59+
const entry = wipMap.get(node)
60+
if (entry) {
61+
const { tag, propsExp } = entry
1062
if (tag.type === NodeTypes.DIRECTIVE) {
1163
// dynamic :tag
1264
context.pushStringPart(`<`)
1365
context.pushStringPart(tag.exp!)
66+
if (propsExp) {
67+
context.pushStringPart(propsExp)
68+
}
1469
context.pushStringPart(`>`)
1570

1671
processChildren(
@@ -30,7 +85,11 @@ export function ssrProcessTransitionGroup(
3085
context.pushStringPart(`>`)
3186
} else {
3287
// static tag
33-
context.pushStringPart(`<${tag.value!.content}>`)
88+
context.pushStringPart(`<${tag.value!.content}`)
89+
if (propsExp) {
90+
context.pushStringPart(propsExp)
91+
}
92+
context.pushStringPart(`>`)
3493
processChildren(node, context, false, true)
3594
context.pushStringPart(`</${tag.value!.content}>`)
3695
}

0 commit comments

Comments
 (0)