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

perf(runtime-vapor): use setAttr or setDOMProp instead of setDynamicProp when possible #291

Merged
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 @@ -151,7 +151,7 @@ export function render(_ctx, $props, $emit, $attrs, $slots) {
`;

exports[`compile > directives > v-pre > should not affect siblings after it 1`] = `
"import { resolveComponent as _resolveComponent, createComponent as _createComponent, createTextNode as _createTextNode, insert as _insert, renderEffect as _renderEffect, setDynamicProp as _setDynamicProp, template as _template } from 'vue/vapor';
"import { resolveComponent as _resolveComponent, createComponent as _createComponent, createTextNode as _createTextNode, insert as _insert, renderEffect as _renderEffect, setDOMProp as _setDOMProp, template as _template } from 'vue/vapor';
const t0 = _template("<div :id=\\"foo\\"><Comp></Comp>{{ bar }}</div>")
const t1 = _template("<div></div>")

Expand All @@ -162,7 +162,7 @@ export function render(_ctx, $props, $emit, $attrs, $slots) {
const n1 = _createComponent(_component_Comp)
const n2 = _createTextNode(() => [_ctx.bar])
_insert([n1, n2], n3)
_renderEffect(() => _setDynamicProp(n3, "id", _ctx.foo))
_renderEffect(() => _setDOMProp(n3, "id", _ctx.foo))
return [n0, n3]
}"
`;
Expand All @@ -177,7 +177,7 @@ export function render(_ctx) {
`;

exports[`compile > dynamic root nodes and interpolation 1`] = `
"import { delegate as _delegate, setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setText as _setText, setDynamicProp as _setDynamicProp, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
"import { delegate as _delegate, setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setText as _setText, setDOMProp as _setDOMProp, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
const t0 = _template("<button></button>")
_delegateEvents("click")

Expand All @@ -186,7 +186,7 @@ export function render(_ctx) {
_delegate(n0, "click", () => _ctx.handleClick)
_setInheritAttrs(["id"])
_renderEffect(() => _setText(n0, _ctx.count, "foo", _ctx.count, "foo", _ctx.count))
_renderEffect(() => _setDynamicProp(n0, "id", _ctx.count, true))
_renderEffect(() => _setDOMProp(n0, "id", _ctx.count, true))
return n0
}"
`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,100 @@ export function render(_ctx) {
}"
`;

exports[`compiler v-bind > HTML global attributes should set as dom prop 1`] = `
"import { setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setDOMProp as _setDOMProp, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")

export function render(_ctx) {
const n0 = t0()
_setInheritAttrs(["id", "title", "lang", "dir", "tabindex"])
_renderEffect(() => _setDOMProp(n0, "id", _ctx.id, true))
_renderEffect(() => _setDOMProp(n0, "title", _ctx.title, true))
_renderEffect(() => _setDOMProp(n0, "lang", _ctx.lang, true))
_renderEffect(() => _setDOMProp(n0, "dir", _ctx.dir, true))
_renderEffect(() => _setDOMProp(n0, "tabindex", _ctx.tabindex, true))
return n0
}"
`;

exports[`compiler v-bind > MathML global attributes should set as dom prop 1`] = `
"import { setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setDOMProp as _setDOMProp, template as _template } from 'vue/vapor';
const t0 = _template("<math></math>")

export function render(_ctx) {
const n0 = t0()
_setInheritAttrs(["autofucus", "dir", "displaystyle", "mathcolor", "tabindex"])
_renderEffect(() => _setDOMProp(n0, "autofucus", _ctx.autofucus, true))
_renderEffect(() => _setDOMProp(n0, "dir", _ctx.dir, true))
_renderEffect(() => _setDOMProp(n0, "displaystyle", _ctx.displaystyle, true))
_renderEffect(() => _setDOMProp(n0, "mathcolor", _ctx.mathcolor, true))
_renderEffect(() => _setDOMProp(n0, "tabindex", _ctx.tabindex, true))
return n0
}"
`;

exports[`compiler v-bind > SVG global attributes should set as dom prop 1`] = `
"import { setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setDOMProp as _setDOMProp, template as _template } from 'vue/vapor';
const t0 = _template("<svg></svg>")

export function render(_ctx) {
const n0 = t0()
_setInheritAttrs(["id", "lang", "tabindex"])
_renderEffect(() => _setDOMProp(n0, "id", _ctx.id, true))
_renderEffect(() => _setDOMProp(n0, "lang", _ctx.lang, true))
_renderEffect(() => _setDOMProp(n0, "tabindex", _ctx.tabindex, true))
return n0
}"
`;

exports[`compiler v-bind > attributes must be set as attribute 1`] = `
"import { renderEffect as _renderEffect, setAttr as _setAttr, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
const t1 = _template("<input>")
const t2 = _template("<textarea></textarea>")
const t3 = _template("<img>")
const t4 = _template("<video></video>")
const t5 = _template("<canvas></canvas>")
const t6 = _template("<source>")

export function render(_ctx) {
const n0 = t0()
const n1 = t1()
const n2 = t2()
const n3 = t3()
const n4 = t4()
const n5 = t5()
const n6 = t6()
_renderEffect(() => _setAttr(n0, "spellcheck", _ctx.spellcheck))
_renderEffect(() => _setAttr(n0, "draggable", _ctx.draggable))
_renderEffect(() => _setAttr(n0, "translate", _ctx.translate))
_renderEffect(() => _setAttr(n0, "form", _ctx.form))
_renderEffect(() => _setAttr(n1, "list", _ctx.list))
_renderEffect(() => _setAttr(n2, "type", _ctx.type))
_renderEffect(() => {
_setAttr(n3, "width", _ctx.width)
_setAttr(n4, "width", _ctx.width)
_setAttr(n5, "width", _ctx.width)
_setAttr(n6, "width", _ctx.width)
})
_renderEffect(() => {
_setAttr(n3, "height", _ctx.height)
_setAttr(n4, "height", _ctx.height)
_setAttr(n5, "height", _ctx.height)
_setAttr(n6, "height", _ctx.height)
})
return [n0, n1, n2, n3, n4, n5, n6]
}"
`;

exports[`compiler v-bind > basic 1`] = `
"import { setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setDynamicProp as _setDynamicProp, template as _template } from 'vue/vapor';
"import { setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setDOMProp as _setDOMProp, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")

export function render(_ctx) {
const n0 = t0()
_setInheritAttrs(["id"])
_renderEffect(() => _setDynamicProp(n0, "id", _ctx.id, true))
_renderEffect(() => _setDOMProp(n0, "id", _ctx.id, true))
return n0
}"
`;
Expand Down Expand Up @@ -170,13 +256,13 @@ export function render(_ctx) {
`;

exports[`compiler v-bind > no expression 1`] = `
"import { setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setDynamicProp as _setDynamicProp, template as _template } from 'vue/vapor';
"import { setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setDOMProp as _setDOMProp, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")

export function render(_ctx) {
const n0 = t0()
_setInheritAttrs(["id"])
_renderEffect(() => _setDynamicProp(n0, "id", _ctx.id, true))
_renderEffect(() => _setDOMProp(n0, "id", _ctx.id, true))
return n0
}"
`;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`compiler: v-once > as root node 1`] = `
"import { setDynamicProp as _setDynamicProp, setInheritAttrs as _setInheritAttrs, template as _template } from 'vue/vapor';
"import { setDOMProp as _setDOMProp, setInheritAttrs as _setInheritAttrs, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")

export function render(_ctx) {
const n0 = t0()
_setDynamicProp(n0, "id", _ctx.foo, true)
_setDOMProp(n0, "id", _ctx.foo, true)
_setInheritAttrs(["id"])
return n0
}"
Expand Down Expand Up @@ -52,13 +52,13 @@ export function render(_ctx) {
`;

exports[`compiler: v-once > on nested plain element 1`] = `
"import { setDynamicProp as _setDynamicProp, template as _template } from 'vue/vapor';
"import { setDOMProp as _setDOMProp, template as _template } from 'vue/vapor';
const t0 = _template("<div><div></div></div>")

export function render(_ctx) {
const n1 = t0()
const n0 = n1.firstChild
_setDynamicProp(n0, "id", _ctx.foo)
_setDOMProp(n0, "id", _ctx.foo)
return n1
}"
`;
Expand Down
71 changes: 69 additions & 2 deletions packages/compiler-vapor/__tests__/transforms/vBind.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ describe('compiler v-bind', () => {
})

expect(code).matchSnapshot()
expect(code).contains('_setDynamicProp(n0, "id", _ctx.id, true)')
expect(code).contains('_setDOMProp(n0, "id", _ctx.id, true)')
})

test('no expression', () => {
Expand Down Expand Up @@ -104,7 +104,7 @@ describe('compiler v-bind', () => {
],
},
})
expect(code).contains('_setDynamicProp(n0, "id", _ctx.id, true)')
expect(code).contains('_setDOMProp(n0, "id", _ctx.id, true)')
})

test('no expression (shorthand)', () => {
Expand Down Expand Up @@ -527,6 +527,73 @@ describe('compiler v-bind', () => {
expect(code).contains('_setAttr(n0, "foo-bar", _ctx.fooBar, true)')
})

test('attributes must be set as attribute', () => {
const { code } = compileWithVBind(`
<div :spellcheck :draggable :translate :form />
<input :list="list" />
<textarea :type="type" />
<img :width="width" :height="height"/>
<video :width="width" :height="height"/>
<canvas :width="width" :height="height"/>
<source :width="width" :height="height"/>
`)

expect(code).matchSnapshot()
expect(code).contains('_setAttr(n0, "spellcheck", _ctx.spellcheck)')
expect(code).contains('_setAttr(n0, "draggable", _ctx.draggable)')
expect(code).contains('_setAttr(n0, "translate", _ctx.translate)')
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(n6, "height", _ctx.height)')
})

test('HTML global attributes should set as dom prop', () => {
const { code } = compileWithVBind(`
<div :id="id" :title="title" :lang="lang" :dir="dir" :tabindex="tabindex" />
`)

expect(code).matchSnapshot()
expect(code).contains('_setDOMProp(n0, "id", _ctx.id, true)')
expect(code).contains('_setDOMProp(n0, "title", _ctx.title, true)')
expect(code).contains('_setDOMProp(n0, "lang", _ctx.lang, true)')
expect(code).contains('_setDOMProp(n0, "dir", _ctx.dir, true)')
expect(code).contains('_setDOMProp(n0, "tabindex", _ctx.tabindex, true)')
})

test('SVG global attributes should set as dom prop', () => {
const { code } = compileWithVBind(`
<svg :id="id" :lang="lang" :tabindex="tabindex" />
`)

expect(code).matchSnapshot()
expect(code).contains('_setDOMProp(n0, "id", _ctx.id, true)')
expect(code).contains('_setDOMProp(n0, "lang", _ctx.lang, true)')
expect(code).contains('_setDOMProp(n0, "tabindex", _ctx.tabindex, true)')
})

test('MathML global attributes should set as dom prop', () => {
const { code } = compileWithVBind(`
<math :autofucus :dir :displaystyle :mathcolor :tabindex/>
`)

expect(code).matchSnapshot()
expect(code).contains('_setDOMProp(n0, "autofucus", _ctx.autofucus, true)')
expect(code).contains('_setDOMProp(n0, "dir", _ctx.dir, true)')
expect(code).contains(
'_setDOMProp(n0, "displaystyle", _ctx.displaystyle, true)',
)
expect(code).contains('_setDOMProp(n0, "mathcolor", _ctx.mathcolor, true)')
expect(code).contains('_setDOMProp(n0, "tabindex", _ctx.tabindex, true)')
})

test('number value', () => {
const { code } = compileWithVBind(`<Comp :depth="0" />`)
expect(code).matchSnapshot()
Expand Down
30 changes: 29 additions & 1 deletion packages/compiler-vapor/src/generators/prop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,17 @@ import {
genCall,
genMulti,
} from './utils'
import { toHandlerKey } from '@vue/shared'
import {
attributeCache,
isHTMLGlobalAttr,
isHTMLTag,
isMathMLGlobalAttr,
isMathMLTag,
isSVGTag,
isSvgGlobalAttr,
shouldSetAsAttr,
toHandlerKey,
} from '@vue/shared'

// only the static key prop will reach here
export function genSetProp(
Expand All @@ -31,9 +41,12 @@ export function genSetProp(
const { vaporHelper } = context
const {
prop: { key, values, modifier },
tag,
} = oper

const keyName = key.content
const tagName = tag.toUpperCase()
const attrCacheKey = `${tagName}_${keyName}`

let helperName: VaporHelper
let omitKey = false
Expand All @@ -45,6 +58,21 @@ export function genSetProp(
omitKey = true
} else if (modifier) {
helperName = modifier === '.' ? 'setDOMProp' : 'setAttr'
} else if (
attributeCache[attrCacheKey] === undefined
? (attributeCache[attrCacheKey] = shouldSetAsAttr(
tag.toUpperCase(),
keyName,
))
: attributeCache[attrCacheKey]
) {
helperName = 'setAttr'
} else if (
(isHTMLTag(tag) && isHTMLGlobalAttr(keyName)) ||
(isSVGTag(tag) && isSvgGlobalAttr(keyName)) ||
(isMathMLTag(tag) && isMathMLGlobalAttr(keyName))
) {
helperName = 'setDOMProp'
} else {
helperName = 'setDynamicProp'
}
Expand Down
1 change: 1 addition & 0 deletions packages/compiler-vapor/src/ir/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ export interface SetPropIRNode extends BaseIRNode {
element: number
prop: IRProp
root: boolean
tag: string
}

export interface SetDynamicPropsIRNode extends BaseIRNode {
Expand Down
1 change: 1 addition & 0 deletions packages/compiler-vapor/src/transforms/transformElement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ function transformNativeElement(
element: context.reference(),
prop,
root: singleRoot,
tag,
})
}
}
Expand Down
Loading