diff --git a/packages/compiler-core/__tests__/transforms/__snapshots__/vIf.spec.ts.snap b/packages/compiler-core/__tests__/transforms/__snapshots__/vIf.spec.ts.snap index 7a4b90413..def7f945a 100644 --- a/packages/compiler-core/__tests__/transforms/__snapshots__/vIf.spec.ts.snap +++ b/packages/compiler-core/__tests__/transforms/__snapshots__/vIf.spec.ts.snap @@ -145,17 +145,3 @@ return function render(_ctx, _cache) { } }" `; - -exports[`compiler: v-if codegen v-if with key 1`] = ` -"const _Vue = Vue - -return function render(_ctx, _cache) { - with (_ctx) { - const { createVNode: _createVNode, openBlock: _openBlock, createBlock: _createBlock, createCommentVNode: _createCommentVNode } = _Vue - - return ok - ? (_openBlock(), _createBlock(\\"div\\", { key: \\"some-key\\" })) - : _createCommentVNode(\\"v-if\\", true) - } -}" -`; diff --git a/packages/compiler-core/__tests__/transforms/vIf.spec.ts b/packages/compiler-core/__tests__/transforms/vIf.spec.ts index 44433d84d..9d4619aa8 100644 --- a/packages/compiler-core/__tests__/transforms/vIf.spec.ts +++ b/packages/compiler-core/__tests__/transforms/vIf.spec.ts @@ -282,6 +282,16 @@ describe('compiler: v-if', () => { } ]) }) + + test('error on user key', () => { + const onError = jest.fn() + parseWithIfTransform(`
`, { onError }) + expect(onError.mock.calls[0]).toMatchObject([ + { + code: ErrorCodes.X_V_IF_KEY + } + ]) + }) }) describe('codegen', () => { @@ -581,18 +591,6 @@ describe('compiler: v-if', () => { expect(branch1.props).toMatchObject(createObjectMatcher({ key: `[0]` })) }) - test('v-if with key', () => { - const { - root, - node: { codegenNode } - } = parseWithIfTransform(``) - expect(codegenNode.consequent).toMatchObject({ - tag: `"div"`, - props: createObjectMatcher({ key: 'some-key' }) - }) - expect(generate(root).code).toMatchSnapshot() - }) - test('with comments', () => { const { node } = parseWithIfTransform(` diff --git a/packages/compiler-core/src/errors.ts b/packages/compiler-core/src/errors.ts index 63c0bb095..4af232163 100644 --- a/packages/compiler-core/src/errors.ts +++ b/packages/compiler-core/src/errors.ts @@ -63,6 +63,7 @@ export const enum ErrorCodes { // transform errors X_V_IF_NO_EXPRESSION, + X_V_IF_KEY, X_V_ELSE_NO_ADJACENT_IF, X_V_FOR_NO_EXPRESSION, X_V_FOR_MALFORMED_EXPRESSION, @@ -135,6 +136,7 @@ export const errorMessages: { [code: number]: string } = { // transform errors [ErrorCodes.X_V_IF_NO_EXPRESSION]: `v-if/v-else-if is missing expression.`, + [ErrorCodes.X_V_IF_KEY]: `v-if branches must use compiler generated keys.`, [ErrorCodes.X_V_ELSE_NO_ADJACENT_IF]: `v-else/v-else-if has no adjacent v-if.`, [ErrorCodes.X_V_FOR_NO_EXPRESSION]: `v-for is missing expression.`, [ErrorCodes.X_V_FOR_MALFORMED_EXPRESSION]: `v-for has invalid expression.`, diff --git a/packages/compiler-core/src/transforms/vIf.ts b/packages/compiler-core/src/transforms/vIf.ts index 491772fca..f22accb30 100644 --- a/packages/compiler-core/src/transforms/vIf.ts +++ b/packages/compiler-core/src/transforms/vIf.ts @@ -30,7 +30,7 @@ import { OPEN_BLOCK, TELEPORT } from '../runtimeHelpers' -import { injectProp, findDir } from '../utils' +import { injectProp, findDir, findProp } from '../utils' import { PatchFlags, PatchFlagNames } from '@vue/shared' export const transformIf = createStructuralDirectiveTransform( @@ -111,6 +111,11 @@ export function processIf( validateBrowserExpression(dir.exp as SimpleExpressionNode, context) } + const userKey = /*#__PURE__*/ findProp(node, 'key') + if (userKey) { + context.onError(createCompilerError(ErrorCodes.X_V_IF_KEY, userKey.loc)) + } + if (dir.name === 'if') { const branch = createIfBranch(node, dir) const ifNode: IfNode = { @@ -175,13 +180,13 @@ function createIfBranch(node: ElementNode, dir: DirectiveNode): IfBranchNode { function createCodegenNodeForBranch( branch: IfBranchNode, - index: number, + keyIndex: number, context: TransformContext ): IfConditionalExpression | BlockCodegenNode { if (branch.condition) { return createConditionalExpression( branch.condition, - createChildrenCodegenNode(branch, index, context), + createChildrenCodegenNode(branch, keyIndex, context), // make sure to pass in asBlock: true so that the comment node call // closes the current block. createCallExpression(context.helper(CREATE_COMMENT), [ @@ -190,19 +195,19 @@ function createCodegenNodeForBranch( ]) ) as IfConditionalExpression } else { - return createChildrenCodegenNode(branch, index, context) + return createChildrenCodegenNode(branch, keyIndex, context) } } function createChildrenCodegenNode( branch: IfBranchNode, - index: number, + keyIndex: number, context: TransformContext ): BlockCodegenNode { const { helper } = context const keyProperty = createObjectProperty( `key`, - createSimpleExpression(index + '', false) + createSimpleExpression(`${keyIndex}`, false) ) const { children } = branch const firstChild = children[0]