Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(compiler-vapor): cache multiple access to the same expression #12568

Merged
merged 20 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,9 @@ export function render(_ctx) {
const n0 = t0()
_delegate(n0, "click", () => _ctx.handleClick)
_renderEffect(() => {
_setText(n0, _ctx.count, "foo", _ctx.count, "foo", _ctx.count)
_setProp(n0, "id", _ctx.count)
const _count = _ctx.count
_setText(n0, _count, "foo", _count, "foo", _count)
_setProp(n0, "id", _count)
})
return n0
}"
Expand All @@ -199,7 +200,10 @@ exports[`compile > expression parsing > interpolation 1`] = `
exports[`compile > expression parsing > v-bind 1`] = `
"
const n0 = t0()
_renderEffect(() => _setDynamicProps(n0, [{ [key.value+1]: _unref(foo)[key.value+1]() }], true))
_renderEffect(() => {
const _key = key.value
_setDynamicProps(n0, [{ [_key+1]: _unref(foo)[_key+1]() }], true)
})
return n0
"
`;
Expand Down
5 changes: 3 additions & 2 deletions packages/compiler-vapor/__tests__/compile.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,10 @@ describe('compile', () => {
},
})
expect(code).matchSnapshot()
expect(code).contains('key.value+1')
expect(code).contains('const _key = key.value')
expect(code).contains('_key+1')
expect(code).contains(
'_setDynamicProps(n0, [{ [key.value+1]: _unref(foo)[key.value+1]() }], true)',
'_setDynamicProps(n0, [{ [_key+1]: _unref(foo)[_key+1]() }], true)',
)
})

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,153 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

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("<div></div>", true)

export function render(_ctx) {
const n0 = t0()
_renderEffect(() => {
const _key = _ctx.key
_setDynamicProps(n0, [{ [_key+1]: _ctx.foo[_key+1]() }], true)
})
return n0
}"
`;

exports[`cache multiple access > dynamic property access 1`] = `
"import { setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue';
const t0 = _template("<div></div>", true)

export function render(_ctx) {
const n0 = t0()
_renderEffect(() => {
const _obj = _ctx.obj
_setProp(n0, "id", _obj[1][_ctx.baz] + _obj.bar)
})
return n0
}"
`;

exports[`cache multiple access > function calls with arguments 1`] = `
"import { setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue';
const t0 = _template("<div></div>")

export function render(_ctx) {
const n0 = t0()
const n1 = t0()
const n2 = t0()
_renderEffect(() => {
const _foo = _ctx.foo
const _bar = _ctx.bar
const _foo_bar_baz = _foo[_bar(_ctx.baz)]

_setProp(n0, "id", _foo_bar_baz)
_setProp(n1, "id", _foo_bar_baz)
_setProp(n2, "id", _bar() + _foo)
})
return [n0, n1, n2]
}"
`;

exports[`cache multiple access > not cache variable and member expression with the same name 1`] = `
"import { setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue';
const t0 = _template("<div></div>", true)

export function render(_ctx) {
const n0 = t0()
_renderEffect(() => _setProp(n0, "id", _ctx.bar + _ctx.obj.bar))
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("<div></div>")

export function render(_ctx) {
const n0 = t0()
const n1 = t0()
_renderEffect(() => {
const _obj = _ctx.obj
const _obj_foo_baz_obj_bar = _obj['foo']['baz'] + _obj.bar

_setProp(n0, "id", _obj_foo_baz_obj_bar)
_setProp(n1, "id", _obj_foo_baz_obj_bar)
})
return [n0, n1]
}"
`;

exports[`cache multiple access > repeated expression in expressions 1`] = `
"import { setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue';
const t0 = _template("<div></div>")

export function render(_ctx) {
const n0 = t0()
const n1 = t0()
const n2 = t0()
_renderEffect(() => {
const _foo = _ctx.foo
const _foo_bar = _foo + _ctx.bar

_setProp(n0, "id", _foo_bar)
_setProp(n1, "id", _foo_bar)
_setProp(n2, "id", _foo + _foo_bar)
})
return [n0, n1, n2]
}"
`;

exports[`cache multiple access > repeated expressions 1`] = `
"import { setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue';
const t0 = _template("<div></div>")

export function render(_ctx) {
const n0 = t0()
const n1 = t0()
_renderEffect(() => {
const _foo_bar = _ctx.foo + _ctx.bar

_setProp(n0, "id", _foo_bar)
_setProp(n1, "id", _foo_bar)
})
return [n0, n1]
}"
`;

exports[`cache multiple access > repeated variable in expressions 1`] = `
"import { setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue';
const t0 = _template("<div></div>")

export function render(_ctx) {
const n0 = t0()
const n1 = t0()
_renderEffect(() => {
const _foo = _ctx.foo
_setProp(n0, "id", _foo + _foo + _ctx.bar)
_setProp(n1, "id", _foo)
})
return [n0, n1]
}"
`;

exports[`cache multiple access > repeated variables 1`] = `
"import { setClass as _setClass, renderEffect as _renderEffect, template as _template } from 'vue';
const t0 = _template("<div></div>")

export function render(_ctx) {
const n0 = t0()
const n1 = t0()
_renderEffect(() => {
const _foo = _ctx.foo

_setClass(n0, _foo)
_setClass(n1, _foo)
})
return [n0, n1]
}"
`;

exports[`compiler v-bind > .attr modifier 1`] = `
"import { setAttr as _setAttr, renderEffect as _renderEffect, template as _template } from 'vue';
const t0 = _template("<div></div>", true)
Expand Down Expand Up @@ -305,22 +453,24 @@ export function render(_ctx) {
const n5 = t5()
const n6 = t6()
_renderEffect(() => {
const _width = _ctx.width
const _height = _ctx.height
_setAttr(n0, "spellcheck", _ctx.spellcheck)
_setAttr(n0, "draggable", _ctx.draggable)
_setAttr(n0, "translate", _ctx.translate)
_setAttr(n0, "form", _ctx.form)
_setAttr(n1, "list", _ctx.list)
_setAttr(n2, "type", _ctx.type)

_setAttr(n3, "width", _ctx.width)
_setAttr(n4, "width", _ctx.width)
_setAttr(n5, "width", _ctx.width)
_setAttr(n6, "width", _ctx.width)
_setAttr(n3, "width", _width)
_setAttr(n4, "width", _width)
_setAttr(n5, "width", _width)
_setAttr(n6, "width", _width)

_setAttr(n3, "height", _ctx.height)
_setAttr(n4, "height", _ctx.height)
_setAttr(n5, "height", _ctx.height)
_setAttr(n6, "height", _ctx.height)
_setAttr(n3, "height", _height)
_setAttr(n4, "height", _height)
_setAttr(n5, "height", _height)
_setAttr(n6, "height", _height)
})
return [n0, n1, n2, n3, n4, n5, n6]
}"
Expand All @@ -343,7 +493,11 @@ const t0 = _template("<div></div>", true)

export function render(_ctx) {
const n0 = t0()
_renderEffect(() => _setDynamicProps(n0, [{ [_ctx.id]: _ctx.id, [_ctx.title]: _ctx.title }], true))
_renderEffect(() => {
const _id = _ctx.id
const _title = _ctx.title
_setDynamicProps(n0, [{ [_id]: _id, [_title]: _title }], true)
})
return n0
}"
`;
Expand All @@ -354,7 +508,10 @@ const t0 = _template("<div></div>", true)

export function render(_ctx) {
const n0 = t0()
_renderEffect(() => _setDynamicProps(n0, [{ [_ctx.id]: _ctx.id, foo: "bar", checked: "" }], true))
_renderEffect(() => {
const _id = _ctx.id
_setDynamicProps(n0, [{ [_id]: _id, foo: "bar", checked: "" }], true)
})
return n0
}"
`;
Expand Down
117 changes: 108 additions & 9 deletions packages/compiler-vapor/__tests__/transforms/vBind.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ describe('compiler v-bind', () => {
],
})
expect(code).contains(
'_setDynamicProps(n0, [{ [_ctx.id]: _ctx.id, [_ctx.title]: _ctx.title }], true)',
'_setDynamicProps(n0, [{ [_id]: _id, [_title]: _title }], true)',
)
})

Expand Down Expand Up @@ -224,7 +224,7 @@ describe('compiler v-bind', () => {
],
})
expect(code).contains(
'_setDynamicProps(n0, [{ [_ctx.id]: _ctx.id, foo: "bar", checked: "" }], true)',
'_setDynamicProps(n0, [{ [_id]: _id, foo: "bar", checked: "" }], true)',
)
})

Expand Down Expand Up @@ -615,13 +615,13 @@ describe('compiler v-bind', () => {
expect(code).contains('_setAttr(n0, "form", _ctx.form)')
expect(code).contains('_setAttr(n1, "list", _ctx.list)')
expect(code).contains('_setAttr(n2, "type", _ctx.type)')
expect(code).contains('_setAttr(n3, "width", _ctx.width)')
expect(code).contains('_setAttr(n3, "height", _ctx.height)')
expect(code).contains('_setAttr(n4, "width", _ctx.width)')
expect(code).contains('_setAttr(n4, "height", _ctx.height)')
expect(code).contains('_setAttr(n5, "width", _ctx.width)')
expect(code).contains('_setAttr(n5, "height", _ctx.height)')
expect(code).contains(' _setAttr(n6, "width", _ctx.width)')
expect(code).contains('_setAttr(n3, "width", _width)')
expect(code).contains('_setAttr(n3, "height", _height)')
expect(code).contains('_setAttr(n4, "width", _width)')
expect(code).contains('_setAttr(n4, "height", _height)')
expect(code).contains('_setAttr(n5, "width", _width)')
expect(code).contains('_setAttr(n5, "height", _height)')
expect(code).contains(' _setAttr(n6, "width", _width)')
})

test(':innerHTML', () => {
Expand Down Expand Up @@ -694,3 +694,102 @@ describe('compiler v-bind', () => {
expect(code).matchSnapshot()
})
})

describe('cache multiple access', () => {
test('repeated variables', () => {
const { code } = compileWithVBind(`
<div :class="foo"></div>
<div :class="foo"></div>
`)
expect(code).matchSnapshot()
expect(code).contains('const _foo = _ctx.foo')
expect(code).contains('setClass(n0, _foo)')
expect(code).contains('setClass(n1, _foo)')
})

test('repeated expressions', () => {
const { code } = compileWithVBind(`
<div :id="foo + bar"></div>
<div :id="foo + bar"></div>
`)
expect(code).matchSnapshot()
expect(code).contains('const _foo_bar = _ctx.foo + _ctx.bar')
expect(code).contains('_setProp(n0, "id", _foo_bar)')
expect(code).contains('_setProp(n1, "id", _foo_bar)')
})

test('repeated variable in expressions', () => {
const { code } = compileWithVBind(`
<div :id="foo + foo + bar"></div>
<div :id="foo"></div>
`)
expect(code).matchSnapshot()
expect(code).contains('const _foo = _ctx.foo')
expect(code).contains('_setProp(n0, "id", _foo + _foo + _ctx.bar)')
expect(code).contains('_setProp(n1, "id", _foo)')
})

test('repeated expression in expressions', () => {
const { code } = compileWithVBind(`
<div :id="foo + bar"></div>
<div :id="foo + bar"></div>
<div :id="foo + foo + bar"></div>
`)
expect(code).matchSnapshot()
expect(code).contains('const _foo_bar = _foo + _ctx.bar')
expect(code).contains('_setProp(n0, "id", _foo_bar)')
expect(code).contains('_setProp(n2, "id", _foo + _foo_bar)')
})

test('function calls with arguments', () => {
const { code } = compileWithVBind(`
<div :id="foo[bar(baz)]"></div>
<div :id="foo[bar(baz)]"></div>
<div :id="bar() + foo"></div>
`)
expect(code).matchSnapshot()
expect(code).contains('const _foo_bar_baz = _foo[_bar(_ctx.baz)]')
expect(code).contains('_setProp(n0, "id", _foo_bar_baz)')
expect(code).contains('_setProp(n1, "id", _foo_bar_baz)')
expect(code).contains('_setProp(n2, "id", _bar() + _foo)')
})

test('dynamic key bindings with expressions', () => {
const { code } = compileWithVBind(`
<div :[key+1]="foo[key+1]()" />
`)
expect(code).matchSnapshot()
expect(code).contains('const _key = _ctx.key')
expect(code).contains('[{ [_key+1]: _ctx.foo[_key+1]() }]')
})

test('object property chain access', () => {
const { code } = compileWithVBind(`
<div :id="obj['foo']['baz'] + obj.bar"></div>
<div :id="obj['foo']['baz'] + obj.bar"></div>
`)
expect(code).matchSnapshot()
expect(code).contains(
"const _obj_foo_baz_obj_bar = _obj['foo']['baz'] + _obj.bar",
)
expect(code).contains('_setProp(n0, "id", _obj_foo_baz_obj_bar)')
expect(code).contains('_setProp(n1, "id", _obj_foo_baz_obj_bar)')
})

test('dynamic property access', () => {
const { code } = compileWithVBind(`
<div :id="obj[1][baz] + obj.bar"></div>
`)
expect(code).matchSnapshot()
expect(code).contains('const _obj = _ctx.obj')
expect(code).contains('_setProp(n0, "id", _obj[1][_ctx.baz] + _obj.bar)')
})

test('not cache variable and member expression with the same name', () => {
const { code } = compileWithVBind(`
<div :id="bar + obj.bar"></div>
`)
expect(code).matchSnapshot()
expect(code).not.contains('const _bar = _ctx.bar')
})
})
Loading
Loading