From ad5bb167096d904a35237dad0dfdaafb33d10151 Mon Sep 17 00:00:00 2001 From: edison Date: Fri, 28 Feb 2025 17:02:52 +0800 Subject: [PATCH] fix(compiler-vapor): properly cache variable used in object property shorthand (#12815) --- .../__snapshots__/vBind.spec.ts.snap | 26 +++++++++++++++++++ .../__tests__/transforms/vBind.spec.ts | 17 ++++++++++++ .../src/generators/expression.ts | 18 +++++++++++-- 3 files changed, 59 insertions(+), 2 deletions(-) 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 24585e39e..6e7d4229d 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vBind.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vBind.spec.ts.snap @@ -1,5 +1,20 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html +exports[`cache multiple access > cache variable used in both property shorthand and normal binding 1`] = ` +"import { setStyle as _setStyle, setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue'; +const t0 = _template("
", true) + +export function render(_ctx) { + const n0 = t0() + _renderEffect(() => { + const _color = _ctx.color + _setStyle(n0, {color: _color}) + _setProp(n0, "id", _color) + }) + return n0 +}" +`; + exports[`cache multiple access > dynamic key bindings with expressions 1`] = ` "import { setDynamicProps as _setDynamicProps, renderEffect as _renderEffect, template as _template } from 'vue'; const t0 = _template("
", true) @@ -60,6 +75,17 @@ export function render(_ctx) { }" `; +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) + +export function render(_ctx) { + const n0 = t0() + _renderEffect(() => _setStyle(n0, {color: _ctx.color})) + return n0 +}" +`; + exports[`cache multiple access > object property chain access 1`] = ` "import { setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue'; const t0 = _template("
") diff --git a/packages/compiler-vapor/__tests__/transforms/vBind.spec.ts b/packages/compiler-vapor/__tests__/transforms/vBind.spec.ts index 5025997e2..9a5f6ab69 100644 --- a/packages/compiler-vapor/__tests__/transforms/vBind.spec.ts +++ b/packages/compiler-vapor/__tests__/transforms/vBind.spec.ts @@ -785,6 +785,23 @@ describe('cache multiple access', () => { expect(code).contains('_setProp(n0, "id", _obj[1][_ctx.baz] + _obj.bar)') }) + test('cache variable used in both property shorthand and normal binding', () => { + const { code } = compileWithVBind(` +
+ `) + expect(code).matchSnapshot() + expect(code).contains('const _color = _ctx.color') + expect(code).contains('_setStyle(n0, {color: _color})') + }) + + test('not cache variable only used in property shorthand', () => { + const { code } = compileWithVBind(` +
+ `) + expect(code).matchSnapshot() + expect(code).not.contains('const _color = _ctx.color') + }) + test('not cache variable and member expression with the same name', () => { const { code } = compileWithVBind(`
diff --git a/packages/compiler-vapor/src/generators/expression.ts b/packages/compiler-vapor/src/generators/expression.ts index e128ccfbe..eedaeeb38 100644 --- a/packages/compiler-vapor/src/generators/expression.ts +++ b/packages/compiler-vapor/src/generators/expression.ts @@ -131,7 +131,11 @@ function genIdentifier( if (idMap && idMap.length) { const replacement = idMap[0] if (isString(replacement)) { - return [[replacement, NewlineType.None, loc]] + if (parent && parent.type === 'ObjectProperty' && parent.shorthand) { + return [[`${name}: ${replacement}`, NewlineType.None, loc]] + } else { + return [[replacement, NewlineType.None, loc]] + } } else { // replacement is an expression - process it again return genExpression(replacement, context, assignment) @@ -292,7 +296,7 @@ function analyzeExpressions(expressions: SimpleExpressionNode[]) { } walk(exp.ast, { - enter(currentNode: Node) { + enter(currentNode: Node, parent: Node | null) { if (currentNode.type === 'MemberExpression') { const memberExp = extractMemberExpression( currentNode, @@ -304,6 +308,16 @@ function analyzeExpressions(expressions: SimpleExpressionNode[]) { 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) }