From aed10c507279900f8afc4861dc01ca4f2b95acb8 Mon Sep 17 00:00:00 2001 From: Evan You Date: Wed, 18 May 2022 09:55:39 +0800 Subject: [PATCH] fix(ssr): render fallthrough attributes for transition-group with tag fix #5141 --- .../__tests__/ssrTransitionGroup.spec.ts | 31 +++++++-- .../src/transforms/ssrTransformComponent.ts | 10 ++- .../transforms/ssrTransformTransitionGroup.ts | 67 +++++++++++++++++-- 3 files changed, 98 insertions(+), 10 deletions(-) diff --git a/packages/compiler-ssr/__tests__/ssrTransitionGroup.spec.ts b/packages/compiler-ssr/__tests__/ssrTransitionGroup.spec.ts index aee771fb3fe..2a3b6d3b4d4 100644 --- a/packages/compiler-ssr/__tests__/ssrTransitionGroup.spec.ts +++ b/packages/compiler-ssr/__tests__/ssrTransitionGroup.spec.ts @@ -26,10 +26,10 @@ describe('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(\`
    \`) + _push(\`\`) _ssrRenderList(_ctx.list, (i) => { _push(\`
    \`) }) @@ -44,10 +44,14 @@ describe('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(\`
    \`) }) @@ -85,4 +89,23 @@ describe('transition-group', () => { }" `) }) + + test('attribute fallthrough', () => { + expect( + compile( + ` + ` + ).code + ).toMatchInlineSnapshot(` + "const { mergeProps: _mergeProps } = require(\\"vue\\") + const { ssrRenderAttrs: _ssrRenderAttrs } = require(\\"vue/server-renderer\\") + + return function ssrRender(_ctx, _push, _parent, _attrs) { + _push(\`
\`) + }" + `) + }) }) diff --git a/packages/compiler-ssr/src/transforms/ssrTransformComponent.ts b/packages/compiler-ssr/src/transforms/ssrTransformComponent.ts index 83d552103ca..4c3a961cd65 100644 --- a/packages/compiler-ssr/src/transforms/ssrTransformComponent.ts +++ b/packages/compiler-ssr/src/transforms/ssrTransformComponent.ts @@ -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. diff --git a/packages/compiler-ssr/src/transforms/ssrTransformTransitionGroup.ts b/packages/compiler-ssr/src/transforms/ssrTransformTransitionGroup.ts index 378c4f333d4..dedf1f64075 100644 --- a/packages/compiler-ssr/src/transforms/ssrTransformTransitionGroup.ts +++ b/packages/compiler-ssr/src/transforms/ssrTransformTransitionGroup.ts @@ -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() + +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(``) }