diff --git a/packages/compiler-dom/src/transforms/Transition.ts b/packages/compiler-dom/src/transforms/Transition.ts
index 85f83adc7..30ea083d8 100644
--- a/packages/compiler-dom/src/transforms/Transition.ts
+++ b/packages/compiler-dom/src/transforms/Transition.ts
@@ -24,6 +24,9 @@ export const transformTransition: NodeTransform = (node, context) => {
export function postTransformTransition(
node: ComponentNode,
onError: (error: CompilerError) => void,
+ hasMultipleChildren: (
+ node: ComponentNode,
+ ) => boolean = defaultHasMultipleChildren,
): () => void {
return () => {
if (!node.children.length) {
@@ -59,7 +62,9 @@ export function postTransformTransition(
}
}
-function hasMultipleChildren(node: ComponentNode | IfBranchNode): boolean {
+function defaultHasMultipleChildren(
+ node: ComponentNode | IfBranchNode,
+): boolean {
// #1352 filter out potential comment nodes.
const children = (node.children = node.children.filter(
c =>
@@ -70,6 +75,7 @@ function hasMultipleChildren(node: ComponentNode | IfBranchNode): boolean {
return (
children.length !== 1 ||
child.type === NodeTypes.FOR ||
- (child.type === NodeTypes.IF && child.branches.some(hasMultipleChildren))
+ (child.type === NodeTypes.IF &&
+ child.branches.some(defaultHasMultipleChildren))
)
}
diff --git a/packages/compiler-vapor/__tests__/transforms/TransformTransition.spec.ts b/packages/compiler-vapor/__tests__/transforms/TransformTransition.spec.ts
index 846179f87..7c86b9f37 100644
--- a/packages/compiler-vapor/__tests__/transforms/TransformTransition.spec.ts
+++ b/packages/compiler-vapor/__tests__/transforms/TransformTransition.spec.ts
@@ -57,21 +57,132 @@ describe('compiler: transition', () => {
expect(code).contains('n0.$key = _ctx.key')
})
- test('warns if multiple children', () => {
+ function checkWarning(template: string, shouldWarn = true) {
const onError = vi.fn()
- compileWithElementTransform(
+ compileWithElementTransform(template, { onError })
+ if (shouldWarn) {
+ expect(onError).toHaveBeenCalled()
+ expect(onError.mock.calls).toMatchObject([
+ [{ code: DOMErrorCodes.X_TRANSITION_INVALID_CHILDREN }],
+ ])
+ } else {
+ expect(onError).not.toHaveBeenCalled()
+ }
+ }
+
+ test('warns if multiple children', () => {
+ checkWarning(
`
foo
bar
`,
- {
- onError,
- },
+ true,
+ )
+ })
+
+ test('warns with v-for', () => {
+ checkWarning(
+ `
+
+ hey
+
+ `,
+ true,
+ )
+ })
+
+ test('warns with multiple v-if + v-for', () => {
+ checkWarning(
+ `
+
+ hey
+ hey
+
+ `,
+ true,
+ )
+ })
+
+ test('warns with template v-if', () => {
+ checkWarning(
+ `
+
+
+
+ `,
+ true,
+ )
+ })
+
+ test('warns with multiple templates', () => {
+ checkWarning(
+ `
+
+
+
+
+ `,
+ true,
+ )
+ })
+
+ test('warns if multiple children with v-if', () => {
+ checkWarning(
+ `
+
+ hey
+ hey
+
+ `,
+ true,
+ )
+ })
+
+ test('does not warn with regular element', () => {
+ checkWarning(
+ `
+
+ hey
+
+ `,
+ false,
+ )
+ })
+
+ test('does not warn with one single v-if', () => {
+ checkWarning(
+ `
+
+ hey
+
+ `,
+ false,
+ )
+ })
+
+ test('does not warn with v-if v-else-if v-else', () => {
+ checkWarning(
+ `
+
+ hey
+ hey
+ hey
+
+ `,
+ false,
+ )
+ })
+
+ test('does not warn with v-if v-else', () => {
+ checkWarning(
+ `
+
+ hey
+ hey
+
+ `,
+ false,
)
- expect(onError).toHaveBeenCalled()
- expect(onError.mock.calls).toMatchObject([
- [{ code: DOMErrorCodes.X_TRANSITION_INVALID_CHILDREN }],
- ])
})
test('inject persisted when child has v-show', () => {
@@ -84,5 +195,21 @@ describe('compiler: transition', () => {
).toMatchSnapshot()
})
- // TODO more tests
+ test('the v-if/else-if/else branches in Transition should ignore comments', () => {
+ expect(
+ compileWithElementTransform(`
+
+ hey
+
+ hey
+
+
+
+ `).code,
+ ).toMatchSnapshot()
+ })
})
diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/TransformTransition.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/TransformTransition.spec.ts.snap
index 4264677c7..a1de229f5 100644
--- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/TransformTransition.spec.ts.snap
+++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/TransformTransition.spec.ts.snap
@@ -35,6 +35,43 @@ export function render(_ctx) {
}"
`;
+exports[`compiler: transition > the v-if/else-if/else branches in Transition should ignore comments 1`] = `
+"import { VaporTransition as _VaporTransition, createIf as _createIf, prepend as _prepend, createComponent as _createComponent, template as _template } from 'vue';
+const t0 = _template("
hey
")
+const t1 = _template("")
+const t2 = _template("")
+
+export function render(_ctx) {
+ const n16 = _createComponent(_VaporTransition, null, {
+ "default": () => {
+ const n0 = _createIf(() => (_ctx.a), () => {
+ const n2 = t0()
+ n2.$key = 2
+ return n2
+ }, () => _createIf(() => (_ctx.b), () => {
+ const n5 = t0()
+ n5.$key = 5
+ return n5
+ }, () => {
+ const n14 = t2()
+ const n9 = _createIf(() => (_ctx.c), () => {
+ const n11 = t1()
+ return n11
+ }, () => {
+ const n13 = t1()
+ return n13
+ })
+ _prepend(n14, n9)
+ n14.$key = 14
+ return n14
+ }))
+ return [n0, n3, n7]
+ }
+ }, true)
+ return n16
+}"
+`;
+
exports[`compiler: transition > work with dynamic keyed children 1`] = `
"import { VaporTransition as _VaporTransition, createKeyedFragment as _createKeyedFragment, createComponent as _createComponent, template as _template } from 'vue';
const t0 = _template("foo
")
diff --git a/packages/compiler-vapor/src/transforms/transformTransition.ts b/packages/compiler-vapor/src/transforms/transformTransition.ts
index 918666dec..857e3bcdf 100644
--- a/packages/compiler-vapor/src/transforms/transformTransition.ts
+++ b/packages/compiler-vapor/src/transforms/transformTransition.ts
@@ -1,7 +1,12 @@
import type { NodeTransform } from '@vue/compiler-vapor'
-import { ElementTypes, NodeTypes } from '@vue/compiler-core'
-import { isTransitionTag } from '../utils'
-import { postTransformTransition } from '@vue/compiler-dom'
+import { findDir, isTransitionTag } from '../utils'
+import {
+ type ElementNode,
+ ElementTypes,
+ NodeTypes,
+ isTemplateNode,
+ postTransformTransition,
+} from '@vue/compiler-dom'
export const transformTransition: NodeTransform = (node, context) => {
if (
@@ -9,7 +14,56 @@ export const transformTransition: NodeTransform = (node, context) => {
node.tagType === ElementTypes.COMPONENT
) {
if (isTransitionTag(node.tag)) {
- return postTransformTransition(node, context.options.onError)
+ return postTransformTransition(
+ node,
+ context.options.onError,
+ hasMultipleChildren,
+ )
}
}
}
+
+function hasMultipleChildren(node: ElementNode): boolean {
+ const children = (node.children = node.children.filter(
+ c =>
+ c.type !== NodeTypes.COMMENT &&
+ !(c.type === NodeTypes.TEXT && !c.content.trim()),
+ ))
+
+ const first = children[0]
+
+ // template
+ if (first && isTemplateNode(first)) {
+ return true
+ }
+
+ // has v-for
+ if (
+ children.length === 1 &&
+ first.type === NodeTypes.ELEMENT &&
+ findDir(first, 'for')
+ ) {
+ return true
+ }
+
+ const hasElse = (node: ElementNode) =>
+ findDir(node, 'else-if') || findDir(node, 'else', true)
+
+ // has v-if/v-else-if/v-else
+ if (
+ children.length > 1 &&
+ children.every(
+ (c, index) =>
+ c.type === NodeTypes.ELEMENT &&
+ // not has v-for
+ !findDir(c, 'for') &&
+ // if the first child has v-if, the rest should also have v-else-if/v-else
+ (index === 0 ? findDir(c, 'if') : hasElse(c)) &&
+ !hasMultipleChildren(c),
+ )
+ ) {
+ return false
+ }
+
+ return children.length > 1
+}