From ebb3eaf970d8d1619a7ba24089c00f0332a6a119 Mon Sep 17 00:00:00 2001 From: linzhe141 <1572213544@qq.com> Date: Tue, 24 Sep 2024 10:00:30 +0800 Subject: [PATCH 1/6] fix(compiler-core): process the keyProp expression --- packages/compiler-core/src/transforms/vFor.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/compiler-core/src/transforms/vFor.ts b/packages/compiler-core/src/transforms/vFor.ts index ec1c21ff88b..2a63d457879 100644 --- a/packages/compiler-core/src/transforms/vFor.ts +++ b/packages/compiler-core/src/transforms/vFor.ts @@ -67,6 +67,13 @@ export const transformFor: NodeTransform = createStructuralDirectiveTransform( // resolve :key shorthand #10882 transformBindShorthand(keyProp, context) } + // #12013 + if (keyProp && keyProp.type !== NodeTypes.ATTRIBUTE && keyProp.exp) { + keyProp.exp = processExpression( + keyProp.exp as SimpleExpressionNode, + context, + ) + } const keyExp = keyProp && (keyProp.type === NodeTypes.ATTRIBUTE From 874281add617703d9ecee3384319540fb64269c0 Mon Sep 17 00:00:00 2001 From: linzhe141 <1572213544@qq.com> Date: Tue, 24 Sep 2024 10:14:02 +0800 Subject: [PATCH 2/6] chore: update --- packages/compiler-core/src/transforms/vFor.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/compiler-core/src/transforms/vFor.ts b/packages/compiler-core/src/transforms/vFor.ts index 2a63d457879..33d88994abf 100644 --- a/packages/compiler-core/src/transforms/vFor.ts +++ b/packages/compiler-core/src/transforms/vFor.ts @@ -67,6 +67,7 @@ export const transformFor: NodeTransform = createStructuralDirectiveTransform( // resolve :key shorthand #10882 transformBindShorthand(keyProp, context) } + // #12013 if (keyProp && keyProp.type !== NodeTypes.ATTRIBUTE && keyProp.exp) { keyProp.exp = processExpression( @@ -74,6 +75,7 @@ export const transformFor: NodeTransform = createStructuralDirectiveTransform( context, ) } + const keyExp = keyProp && (keyProp.type === NodeTypes.ATTRIBUTE @@ -95,12 +97,6 @@ export const transformFor: NodeTransform = createStructuralDirectiveTransform( context, ) } - if (keyProperty && keyProp!.type !== NodeTypes.ATTRIBUTE) { - keyProperty.value = processExpression( - keyProperty.value as SimpleExpressionNode, - context, - ) - } } const isStableFragment = From 3ebf43bb5a587d46475c1d519d31564d416422c7 Mon Sep 17 00:00:00 2001 From: linzhe141 <1572213544@qq.com> Date: Tue, 24 Sep 2024 11:09:12 +0800 Subject: [PATCH 3/6] chore: update Co-authored-by: edison --- .../__tests__/transforms/vFor.spec.ts | 14 +++++++++ .../src/transforms/transformExpression.ts | 12 ++++++-- packages/compiler-core/src/transforms/vFor.ts | 29 ++++++++++++------- 3 files changed, 42 insertions(+), 13 deletions(-) diff --git a/packages/compiler-core/__tests__/transforms/vFor.spec.ts b/packages/compiler-core/__tests__/transforms/vFor.spec.ts index fead2476ac5..43061a8ae7a 100644 --- a/packages/compiler-core/__tests__/transforms/vFor.spec.ts +++ b/packages/compiler-core/__tests__/transforms/vFor.spec.ts @@ -667,6 +667,20 @@ describe('compiler: v-for', () => { }) }) + test('element v-for key expression prefixing + v-memo', () => { + const { + node: { codegenNode }, + } = parseWithForTransform( + '', + { prefixIdentifiers: true }, + ) + const keyExp = + // @ts-expect-error + codegenNode.children.arguments[1].body.body[1].children[2].children[0] + .content + expect(keyExp).toBe('_ctx.getId') + }) + test('template v-for key no prefixing on attribute key', () => { const { node: { codegenNode }, diff --git a/packages/compiler-core/src/transforms/transformExpression.ts b/packages/compiler-core/src/transforms/transformExpression.ts index ec2d4685314..9ae8897e674 100644 --- a/packages/compiler-core/src/transforms/transformExpression.ts +++ b/packages/compiler-core/src/transforms/transformExpression.ts @@ -24,7 +24,7 @@ import { isStaticPropertyKey, walkIdentifiers, } from '../babelUtils' -import { advancePositionWithClone, isSimpleIdentifier } from '../utils' +import { advancePositionWithClone, findDir, isSimpleIdentifier } from '../utils' import { genPropsAccessExp, hasOwn, @@ -54,6 +54,7 @@ export const transformExpression: NodeTransform = (node, context) => { ) } else if (node.type === NodeTypes.ELEMENT) { // handle directives on element + const memo = findDir(node, 'memo') for (let i = 0; i < node.props.length; i++) { const dir = node.props[i] // do not process for v-on & v-for since they are special handled @@ -65,7 +66,14 @@ export const transformExpression: NodeTransform = (node, context) => { if ( exp && exp.type === NodeTypes.SIMPLE_EXPRESSION && - !(dir.name === 'on' && arg) + !(dir.name === 'on' && arg) && + // key has been processed in transformFor(vMemo + vFor) + !( + memo && + arg && + arg.type === NodeTypes.SIMPLE_EXPRESSION && + arg.content === 'key' + ) ) { dir.exp = processExpression( exp, diff --git a/packages/compiler-core/src/transforms/vFor.ts b/packages/compiler-core/src/transforms/vFor.ts index 33d88994abf..0dca0ba9ab4 100644 --- a/packages/compiler-core/src/transforms/vFor.ts +++ b/packages/compiler-core/src/transforms/vFor.ts @@ -63,26 +63,27 @@ export const transformFor: NodeTransform = createStructuralDirectiveTransform( const isTemplate = isTemplateNode(node) const memo = findDir(node, 'memo') const keyProp = findProp(node, `key`, false, true) - if (keyProp && keyProp.type === NodeTypes.DIRECTIVE && !keyProp.exp) { + const isDirKey = keyProp && keyProp.type === NodeTypes.DIRECTIVE + if (isDirKey && !keyProp.exp) { // resolve :key shorthand #10882 transformBindShorthand(keyProp, context) } - - // #12013 - if (keyProp && keyProp.type !== NodeTypes.ATTRIBUTE && keyProp.exp) { - keyProp.exp = processExpression( - keyProp.exp as SimpleExpressionNode, - context, - ) - } - - const keyExp = + let keyExp = keyProp && (keyProp.type === NodeTypes.ATTRIBUTE ? keyProp.value ? createSimpleExpression(keyProp.value.content, true) : undefined : keyProp.exp) + + if (memo && keyExp && isDirKey) { + if (!__BROWSER__) { + keyProp.exp = keyExp = processExpression( + keyExp as SimpleExpressionNode, + context, + ) + } + } const keyProperty = keyProp && keyExp ? createObjectProperty(`key`, keyExp) : null @@ -97,6 +98,12 @@ export const transformFor: NodeTransform = createStructuralDirectiveTransform( context, ) } + if (keyProperty && keyProp!.type !== NodeTypes.ATTRIBUTE) { + keyProperty.value = processExpression( + keyProperty.value as SimpleExpressionNode, + context, + ) + } } const isStableFragment = From 59db93e1f2a850e4a8fbe3bc64dee5d105959427 Mon Sep 17 00:00:00 2001 From: linzhe141 <1572213544@qq.com> Date: Tue, 24 Sep 2024 11:22:41 +0800 Subject: [PATCH 4/6] chore: update test --- .../__tests__/transforms/vFor.spec.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/compiler-core/__tests__/transforms/vFor.spec.ts b/packages/compiler-core/__tests__/transforms/vFor.spec.ts index 43061a8ae7a..d0aecc4e0da 100644 --- a/packages/compiler-core/__tests__/transforms/vFor.spec.ts +++ b/packages/compiler-core/__tests__/transforms/vFor.spec.ts @@ -676,9 +676,18 @@ describe('compiler: v-for', () => { ) const keyExp = // @ts-expect-error - codegenNode.children.arguments[1].body.body[1].children[2].children[0] - .content - expect(keyExp).toBe('_ctx.getId') + codegenNode.children.arguments[1].body.body[1].children[2] + expect(keyExp).toMatchObject({ + type: NodeTypes.COMPOUND_EXPRESSION, + children: [ + // should prefix outer scope references + { content: `_ctx.getId` }, + `(`, + // should NOT prefix in scope variables + { content: `data` }, + `)`, + ], + }) }) test('template v-for key no prefixing on attribute key', () => { From 3edffcbba68543afc48eaee33c012d4e04a63330 Mon Sep 17 00:00:00 2001 From: linzhe141 <1572213544@qq.com> Date: Tue, 24 Sep 2024 13:06:32 +0800 Subject: [PATCH 5/6] chore: update test --- .../__tests__/transforms/vMemo.spec.ts | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/packages/compiler-core/__tests__/transforms/vMemo.spec.ts b/packages/compiler-core/__tests__/transforms/vMemo.spec.ts index 85769e6e977..ba6752241eb 100644 --- a/packages/compiler-core/__tests__/transforms/vMemo.spec.ts +++ b/packages/compiler-core/__tests__/transforms/vMemo.spec.ts @@ -1,4 +1,5 @@ -import { baseCompile } from '../../src' +import { NodeTypes, baseCompile } from '../../src' +import { parseWithForTransform } from './vFor.spec' describe('compiler: v-memo transform', () => { function compile(content: string) { @@ -53,4 +54,27 @@ describe('compiler: v-memo transform', () => { ), ).toMatchSnapshot() }) + + test('element v-for key expression prefixing + v-memo', () => { + const { + node: { codegenNode }, + } = parseWithForTransform( + '', + { prefixIdentifiers: true }, + ) + const keyExp = + // @ts-expect-error + codegenNode.children.arguments[1].body.body[1].children[2] + expect(keyExp).toMatchObject({ + type: NodeTypes.COMPOUND_EXPRESSION, + children: [ + // should prefix outer scope references + { content: `_ctx.getId` }, + `(`, + // should NOT prefix in scope variables + { content: `data` }, + `)`, + ], + }) + }) }) From b709510d7ce7749be667c238bf993000579facd6 Mon Sep 17 00:00:00 2001 From: linzhe141 <1572213544@qq.com> Date: Tue, 24 Sep 2024 13:15:21 +0800 Subject: [PATCH 6/6] chore: update test --- .../__snapshots__/vMemo.spec.ts.snap | 18 ++++++++++++ .../__tests__/transforms/vFor.spec.ts | 23 --------------- .../__tests__/transforms/vMemo.spec.ts | 28 ++++--------------- 3 files changed, 24 insertions(+), 45 deletions(-) diff --git a/packages/compiler-core/__tests__/transforms/__snapshots__/vMemo.spec.ts.snap b/packages/compiler-core/__tests__/transforms/__snapshots__/vMemo.spec.ts.snap index 220bc177418..86e0b3d2fd5 100644 --- a/packages/compiler-core/__tests__/transforms/__snapshots__/vMemo.spec.ts.snap +++ b/packages/compiler-core/__tests__/transforms/__snapshots__/vMemo.spec.ts.snap @@ -1,5 +1,23 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html +exports[`compiler: v-memo transform > element v-for key expression prefixing + v-memo 1`] = ` +"import { renderList as _renderList, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock, isMemoSame as _isMemoSame, withMemo as _withMemo } from "vue" + +export function render(_ctx, _cache) { + return (_openBlock(), _createElementBlock("div", null, [ + (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(_ctx.tableData, (data, __, ___, _cached) => { + const _memo = (_ctx.getLetter(data)) + if (_cached && _cached.key === _ctx.getId(data) && _isMemoSame(_cached, _memo)) return _cached + const _item = (_openBlock(), _createElementBlock("span", { + key: _ctx.getId(data) + })) + _item.memo = _memo + return _item + }, _cache, 0), 128 /* KEYED_FRAGMENT */)) + ])) +}" +`; + exports[`compiler: v-memo transform > on component 1`] = ` "import { resolveComponent as _resolveComponent, createVNode as _createVNode, withMemo as _withMemo, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue" diff --git a/packages/compiler-core/__tests__/transforms/vFor.spec.ts b/packages/compiler-core/__tests__/transforms/vFor.spec.ts index d0aecc4e0da..fead2476ac5 100644 --- a/packages/compiler-core/__tests__/transforms/vFor.spec.ts +++ b/packages/compiler-core/__tests__/transforms/vFor.spec.ts @@ -667,29 +667,6 @@ describe('compiler: v-for', () => { }) }) - test('element v-for key expression prefixing + v-memo', () => { - const { - node: { codegenNode }, - } = parseWithForTransform( - '', - { prefixIdentifiers: true }, - ) - const keyExp = - // @ts-expect-error - codegenNode.children.arguments[1].body.body[1].children[2] - expect(keyExp).toMatchObject({ - type: NodeTypes.COMPOUND_EXPRESSION, - children: [ - // should prefix outer scope references - { content: `_ctx.getId` }, - `(`, - // should NOT prefix in scope variables - { content: `data` }, - `)`, - ], - }) - }) - test('template v-for key no prefixing on attribute key', () => { const { node: { codegenNode }, diff --git a/packages/compiler-core/__tests__/transforms/vMemo.spec.ts b/packages/compiler-core/__tests__/transforms/vMemo.spec.ts index ba6752241eb..41e7d922ebe 100644 --- a/packages/compiler-core/__tests__/transforms/vMemo.spec.ts +++ b/packages/compiler-core/__tests__/transforms/vMemo.spec.ts @@ -1,5 +1,4 @@ -import { NodeTypes, baseCompile } from '../../src' -import { parseWithForTransform } from './vFor.spec' +import { baseCompile } from '../../src' describe('compiler: v-memo transform', () => { function compile(content: string) { @@ -56,25 +55,10 @@ describe('compiler: v-memo transform', () => { }) test('element v-for key expression prefixing + v-memo', () => { - const { - node: { codegenNode }, - } = parseWithForTransform( - '', - { prefixIdentifiers: true }, - ) - const keyExp = - // @ts-expect-error - codegenNode.children.arguments[1].body.body[1].children[2] - expect(keyExp).toMatchObject({ - type: NodeTypes.COMPOUND_EXPRESSION, - children: [ - // should prefix outer scope references - { content: `_ctx.getId` }, - `(`, - // should NOT prefix in scope variables - { content: `data` }, - `)`, - ], - }) + expect( + compile( + ``, + ), + ).toMatchSnapshot() }) })