Skip to content

Commit 4cc39e1

Browse files
committed
feat(compiler): warn invalid children for transition and keep-alive
1 parent 605cc3d commit 4cc39e1

File tree

5 files changed

+46
-2
lines changed

5 files changed

+46
-2
lines changed

packages/compiler-core/src/errors.ts

+2
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ export const enum ErrorCodes {
8181
X_V_MODEL_MALFORMED_EXPRESSION,
8282
X_V_MODEL_ON_SCOPE_VARIABLE,
8383
X_INVALID_EXPRESSION,
84+
X_KEEP_ALIVE_INVALID_CHILDREN,
8485

8586
// generic errors
8687
X_PREFIX_ID_NOT_SUPPORTED,
@@ -174,6 +175,7 @@ export const errorMessages: { [code: number]: string } = {
174175
[ErrorCodes.X_V_MODEL_MALFORMED_EXPRESSION]: `v-model value must be a valid JavaScript member expression.`,
175176
[ErrorCodes.X_V_MODEL_ON_SCOPE_VARIABLE]: `v-model cannot be used on v-for or v-slot scope variables because they are not writable.`,
176177
[ErrorCodes.X_INVALID_EXPRESSION]: `Invalid JavaScript expression.`,
178+
[ErrorCodes.X_KEEP_ALIVE_INVALID_CHILDREN]: `<KeepAlive> expects exactly one child component.`,
177179

178180
// generic errors
179181
[ErrorCodes.X_PREFIX_ID_NOT_SUPPORTED]: `"prefixIdentifiers" option is not supported in this build of compiler.`,

packages/compiler-core/src/transforms/transformElement.ts

+11
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,17 @@ export const transformElement: NodeTransform = (node, context) => {
100100
if (!hasProps) {
101101
args.push(`null`)
102102
}
103+
104+
if (__DEV__ && nodeType === KEEP_ALIVE && node.children.length > 1) {
105+
context.onError(
106+
createCompilerError(ErrorCodes.X_KEEP_ALIVE_INVALID_CHILDREN, {
107+
start: node.children[0].loc.start,
108+
end: node.children[node.children.length - 1].loc.end,
109+
source: ''
110+
})
111+
)
112+
}
113+
103114
// Portal & KeepAlive should have normal children instead of slots
104115
// Portal is not a real component has dedicated handling in the renderer
105116
// KeepAlive should not track its own deps so that it can be used inside

packages/compiler-dom/src/errors.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export const enum DOMErrorCodes {
3030
X_V_MODEL_ON_FILE_INPUT_ELEMENT,
3131
X_V_MODEL_UNNECESSARY_VALUE,
3232
X_V_SHOW_NO_EXPRESSION,
33+
X_TRANSITION_INVALID_CHILDREN,
3334
__EXTEND_POINT__
3435
}
3536

@@ -42,5 +43,6 @@ export const DOMErrorMessages: { [code: number]: string } = {
4243
[DOMErrorCodes.X_V_MODEL_ARG_ON_ELEMENT]: `v-model argument is not supported on plain elements.`,
4344
[DOMErrorCodes.X_V_MODEL_ON_FILE_INPUT_ELEMENT]: `v-model cannot used on file inputs since they are read-only. Use a v-on:change listener instead.`,
4445
[DOMErrorCodes.X_V_MODEL_UNNECESSARY_VALUE]: `Unnecessary value binding used alongside v-model. It will interfere with v-model's behavior.`,
45-
[DOMErrorCodes.X_V_SHOW_NO_EXPRESSION]: `v-show is missing expression.`
46+
[DOMErrorCodes.X_V_SHOW_NO_EXPRESSION]: `v-show is missing expression.`,
47+
[DOMErrorCodes.X_TRANSITION_INVALID_CHILDREN]: `<Transition> expects exactly one child element or component.`
4648
}

packages/compiler-dom/src/index.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { transformModel } from './transforms/vModel'
1717
import { transformOn } from './transforms/vOn'
1818
import { transformShow } from './transforms/vShow'
1919
import { TRANSITION, TRANSITION_GROUP } from './runtimeHelpers'
20+
import { warnTransitionChildren } from './transforms/warnTransitionChildren'
2021

2122
export const parserOptions = __BROWSER__
2223
? parserOptionsMinimal
@@ -37,7 +38,11 @@ export function compile(
3738
return baseCompile(template, {
3839
...parserOptions,
3940
...options,
40-
nodeTransforms: [transformStyle, ...(options.nodeTransforms || [])],
41+
nodeTransforms: [
42+
transformStyle,
43+
...(__DEV__ ? [warnTransitionChildren] : []),
44+
...(options.nodeTransforms || [])
45+
],
4146
directiveTransforms: {
4247
cloak: noopDirectiveTransform,
4348
html: transformVHtml,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { NodeTransform, NodeTypes, ElementTypes } from '@vue/compiler-core'
2+
import { TRANSITION } from '../runtimeHelpers'
3+
import { createDOMCompilerError, DOMErrorCodes } from '../errors'
4+
5+
export const warnTransitionChildren: NodeTransform = (node, context) => {
6+
if (
7+
node.type === NodeTypes.ELEMENT &&
8+
node.tagType === ElementTypes.COMPONENT
9+
) {
10+
const component = context.isBuiltInComponent(node.tag)
11+
if (
12+
component === TRANSITION &&
13+
(node.children.length > 1 || node.children[0].type === NodeTypes.FOR)
14+
) {
15+
context.onError(
16+
createDOMCompilerError(DOMErrorCodes.X_TRANSITION_INVALID_CHILDREN, {
17+
start: node.children[0].loc.start,
18+
end: node.children[node.children.length - 1].loc.end,
19+
source: ''
20+
})
21+
)
22+
}
23+
}
24+
}

0 commit comments

Comments
 (0)