From 3f62257a46199711f66c696e43a37b883e767c8d Mon Sep 17 00:00:00 2001 From: daiwei Date: Mon, 24 Nov 2025 17:32:00 +0800 Subject: [PATCH 1/2] fix(compiler-vapor): improve expression caching for shared member roots --- .../transforms/__snapshots__/vBind.spec.ts.snap | 16 ++++++++++++++++ .../__tests__/transforms/vBind.spec.ts | 11 +++++++++++ .../compiler-vapor/src/generators/expression.ts | 6 +++--- 3 files changed, 30 insertions(+), 3 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 e19adce62af..151fefe4fdd 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vBind.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vBind.spec.ts.snap @@ -238,6 +238,22 @@ export function render(_ctx) { }" `; +exports[`cache multiple access > shared member root 1`] = ` +"import { setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue'; +const t0 = _template("
") + +export function render(_ctx) { + const n0 = t0() + const n1 = t0() + _renderEffect(() => { + const _foo = _ctx.foo + _setProp(n0, "id", _foo.bar) + _setProp(n1, "id", _foo.baz) + }) + return [n0, n1] +}" +`; + exports[`cache multiple access > variable name substring edge cases 1`] = ` "import { setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue'; const t0 = _template("
", true) diff --git a/packages/compiler-vapor/__tests__/transforms/vBind.spec.ts b/packages/compiler-vapor/__tests__/transforms/vBind.spec.ts index 0d60c02fd54..697a3204a94 100644 --- a/packages/compiler-vapor/__tests__/transforms/vBind.spec.ts +++ b/packages/compiler-vapor/__tests__/transforms/vBind.spec.ts @@ -853,6 +853,17 @@ describe('cache multiple access', () => { expect(code).contains('_setProp(n0, "id", _obj.foo + _obj.bar)') }) + test('shared member root', () => { + const { code } = compileWithVBind(` +
+
+ `) + expect(code).matchSnapshot() + expect(code).contains('const _foo = _ctx.foo') + expect(code).contains('_setProp(n0, "id", _foo.bar)') + expect(code).contains('_setProp(n1, "id", _foo.baz)') + }) + test('not cache variable only used in property shorthand', () => { const { code } = compileWithVBind(`
diff --git a/packages/compiler-vapor/src/generators/expression.ts b/packages/compiler-vapor/src/generators/expression.ts index 75803d5629b..2c33b4ab85a 100644 --- a/packages/compiler-vapor/src/generators/expression.ts +++ b/packages/compiler-vapor/src/generators/expression.ts @@ -492,10 +492,10 @@ function shouldDeclareVariable( } return true } - // if arrays share common elements, no declaration needed - // because they will be treat as repeated expressions + // if arrays are identical, no declaration needed + // because they will be treated as repeated expressions // e.g., [[foo,bar],[foo,bar]] -> const foo_bar = _ctx.foo + _ctx.bar - if (vars.some(v => v.some(e => first.includes(e)))) { + if (vars.every(v => v.every((e, idx) => e === first[idx]))) { return false } From 9e47f5adb70627247f0c487e7b616ac2d0a7b05f Mon Sep 17 00:00:00 2001 From: daiwei Date: Mon, 24 Nov 2025 17:53:52 +0800 Subject: [PATCH 2/2] fix(compiler-vapor): handle TSNonNullExpression correctly in expression caching --- .../__snapshots__/vBind.spec.ts.snap | 18 +++++++++++++++++- .../__tests__/transforms/vBind.spec.ts | 13 ++++++++++++- .../src/generators/expression.ts | 2 +- 3 files changed, 30 insertions(+), 3 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 151fefe4fdd..e2c94526b9b 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vBind.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vBind.spec.ts.snap @@ -8,7 +8,7 @@ export function render(_ctx) { const n0 = t0() _renderEffect(() => { const _obj = _ctx.obj - _setProp(n0, "id", _obj.foo + _obj.bar) + _setProp(n0, "id", _obj!.foo + _obj!.bar) }) return n0 }" @@ -254,6 +254,22 @@ export function render(_ctx) { }" `; +exports[`cache multiple access > shared member root with TSNonNullExpression 1`] = ` +"import { setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue'; +const t0 = _template("
") + +export function render(_ctx) { + const n0 = t0() + const n1 = t0() + _renderEffect(() => { + const _foo = _ctx.foo + _setProp(n0, "id", _foo!.bar) + _setProp(n1, "id", _foo!.baz) + }) + return [n0, n1] +}" +`; + exports[`cache multiple access > variable name substring edge cases 1`] = ` "import { setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue'; const t0 = _template("
", true) diff --git a/packages/compiler-vapor/__tests__/transforms/vBind.spec.ts b/packages/compiler-vapor/__tests__/transforms/vBind.spec.ts index 697a3204a94..230ae2c4da4 100644 --- a/packages/compiler-vapor/__tests__/transforms/vBind.spec.ts +++ b/packages/compiler-vapor/__tests__/transforms/vBind.spec.ts @@ -850,7 +850,7 @@ describe('cache multiple access', () => { const { code } = compileWithVBind(`
`) expect(code).matchSnapshot() expect(code).contains('const _obj = _ctx.obj') - expect(code).contains('_setProp(n0, "id", _obj.foo + _obj.bar)') + expect(code).contains('_setProp(n0, "id", _obj!.foo + _obj!.bar)') }) test('shared member root', () => { @@ -864,6 +864,17 @@ describe('cache multiple access', () => { expect(code).contains('_setProp(n1, "id", _foo.baz)') }) + test('shared member root with TSNonNullExpression', () => { + const { code } = compileWithVBind(` +
+
+ `) + expect(code).matchSnapshot() + expect(code).contains('const _foo = _ctx.foo') + expect(code).contains('_setProp(n0, "id", _foo!.bar)') + expect(code).contains('_setProp(n1, "id", _foo!.baz)') + }) + test('not cache variable only used in property shorthand', () => { const { code } = compileWithVBind(`
diff --git a/packages/compiler-vapor/src/generators/expression.ts b/packages/compiler-vapor/src/generators/expression.ts index 2c33b4ab85a..9012ee1f2e1 100644 --- a/packages/compiler-vapor/src/generators/expression.ts +++ b/packages/compiler-vapor/src/generators/expression.ts @@ -679,7 +679,7 @@ function extractMemberExpression( : `.${extractMemberExpression(exp.property, NOOP)}` return `${object}${prop}` case 'TSNonNullExpression': // foo!.bar - return `${extractMemberExpression(exp.expression, onIdentifier)}!` + return `${extractMemberExpression(exp.expression, onIdentifier)}` default: return '' }