diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformTemplateRef.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformTemplateRef.spec.ts.snap index f2eade4bcdf..4a691056ae2 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformTemplateRef.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformTemplateRef.spec.ts.snap @@ -13,6 +13,19 @@ export function render(_ctx) { }" `; +exports[`compiler: template ref transform > function ref 1`] = ` +"import { createTemplateRefSetter as _createTemplateRefSetter, renderEffect as _renderEffect, template as _template } from 'vue'; +const t0 = _template("
", true) + +export function render(_ctx) { + const _setTemplateRef = _createTemplateRefSetter() + const n0 = t0() + let r0 + _renderEffect(() => r0 = _setTemplateRef(n0, bar => _ctx.foo = bar, r0)) + return n0 +}" +`; + exports[`compiler: template ref transform > ref + v-for 1`] = ` "import { createTemplateRefSetter as _createTemplateRefSetter, createFor as _createFor, template as _template } from 'vue'; const t0 = _template("
", true) diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vBind.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vBind.spec.ts.snap index 6e7d4229df8..9ffac2fb932 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vBind.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vBind.spec.ts.snap @@ -75,6 +75,17 @@ export function render(_ctx) { }" `; +exports[`cache multiple access > not cache variable in function expression 1`] = ` +"import { setDynamicProps as _setDynamicProps, renderEffect as _renderEffect, template as _template } from 'vue'; +const t0 = _template("
", true) + +export function render(_ctx) { + const n0 = t0() + _renderEffect(() => _setDynamicProps(n0, [{ foo: bar => _ctx.foo = bar }], true)) + return n0 +}" +`; + exports[`cache multiple access > not cache variable only used in property shorthand 1`] = ` "import { setStyle as _setStyle, renderEffect as _renderEffect, template as _template } from 'vue'; const t0 = _template("
", true) diff --git a/packages/compiler-vapor/__tests__/transforms/transformTemplateRef.spec.ts b/packages/compiler-vapor/__tests__/transforms/transformTemplateRef.spec.ts index 6be8f18779c..f026675e4eb 100644 --- a/packages/compiler-vapor/__tests__/transforms/transformTemplateRef.spec.ts +++ b/packages/compiler-vapor/__tests__/transforms/transformTemplateRef.spec.ts @@ -81,6 +81,40 @@ describe('compiler: template ref transform', () => { expect(code).contains('_setTemplateRef(n0, _ctx.foo, r0)') }) + test('function ref', () => { + const { ir, code } = compileWithTransformRef( + `
`, + ) + expect(ir.block.dynamic.children[0]).toMatchObject({ + id: 0, + flags: DynamicFlag.REFERENCED, + }) + expect(ir.template).toEqual(['
']) + expect(ir.block.operation).toMatchObject([ + { + type: IRNodeTypes.DECLARE_OLD_REF, + id: 0, + }, + ]) + expect(ir.block.effect).toMatchObject([ + { + operations: [ + { + type: IRNodeTypes.SET_TEMPLATE_REF, + element: 0, + value: { + content: 'bar => foo = bar', + isStatic: false, + }, + }, + ], + }, + ]) + expect(code).toMatchSnapshot() + expect(code).contains('const _setTemplateRef = _createTemplateRefSetter()') + expect(code).contains('_setTemplateRef(n0, bar => _ctx.foo = bar, r0)') + }) + test('ref + v-if', () => { const { ir, code } = compileWithTransformRef( `
`, diff --git a/packages/compiler-vapor/__tests__/transforms/vBind.spec.ts b/packages/compiler-vapor/__tests__/transforms/vBind.spec.ts index 9a5f6ab6971..60c3ebf0c27 100644 --- a/packages/compiler-vapor/__tests__/transforms/vBind.spec.ts +++ b/packages/compiler-vapor/__tests__/transforms/vBind.spec.ts @@ -809,4 +809,12 @@ describe('cache multiple access', () => { expect(code).matchSnapshot() expect(code).not.contains('const _bar = _ctx.bar') }) + + test('not cache variable in function expression', () => { + const { code } = compileWithVBind(` +
+ `) + expect(code).matchSnapshot() + expect(code).not.contains('const _bar = _ctx.bar') + }) }) diff --git a/packages/compiler-vapor/src/generators/expression.ts b/packages/compiler-vapor/src/generators/expression.ts index eedaeeb380a..eab50c62591 100644 --- a/packages/compiler-vapor/src/generators/expression.ts +++ b/packages/compiler-vapor/src/generators/expression.ts @@ -20,7 +20,6 @@ import type { Identifier, Node } from '@babel/types' import type { CodegenContext } from '../generate' import { isConstantExpression } from '../utils' import { type CodeFragment, NEWLINE, buildCodeFragment } from './utils' -import { walk } from 'estree-walker' import { type ParserOptions, parseExpression } from '@babel/parser' export function genExpression( @@ -295,33 +294,15 @@ function analyzeExpressions(expressions: SimpleExpressionNode[]) { continue } - walk(exp.ast, { - enter(currentNode: Node, parent: Node | null) { - if (currentNode.type === 'MemberExpression') { - const memberExp = extractMemberExpression( - currentNode, - (name: string) => { - registerVariable(name, exp, true) - }, - ) - registerVariable(memberExp, exp, false) - return this.skip() - } - - // skip shorthand or non-computed property keys - if ( - parent && - parent.type === 'ObjectProperty' && - parent.key === currentNode && - (parent.shorthand || !parent.computed) - ) { - return this.skip() - } - - if (currentNode.type === 'Identifier') { - registerVariable(currentNode.name, exp, true) - } - }, + walkIdentifiers(exp.ast, (currentNode, parent, parentStack) => { + if (parent && isMemberExpression(parent)) { + const memberExp = extractMemberExpression(parent, name => { + registerVariable(name, exp, true) + }) + registerVariable(memberExp, exp, false) + } else if (!parentStack.some(isMemberExpression)) { + registerVariable(currentNode.name, exp, true) + } }) } @@ -580,3 +561,9 @@ function extractMemberExpression( return '' } } + +const isMemberExpression = (node: Node) => { + return ( + node.type === 'MemberExpression' || node.type === 'OptionalMemberExpression' + ) +}