mirror of https://github.com/vuejs/core.git
fix(compiler-vapor): correct execution order of operations (#13351)
This commit is contained in:
parent
430216a9f5
commit
bf7424aa29
|
@ -149,7 +149,7 @@ export function render(_ctx, $props, $emit, $attrs, $slots) {
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`compile > directives > v-pre > should not affect siblings after it 1`] = `
|
exports[`compile > directives > v-pre > should not affect siblings after it 1`] = `
|
||||||
"import { resolveComponent as _resolveComponent, setInsertionState as _setInsertionState, createComponentWithFallback as _createComponentWithFallback, child as _child, toDisplayString as _toDisplayString, setText as _setText, setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue';
|
"import { resolveComponent as _resolveComponent, setInsertionState as _setInsertionState, createComponentWithFallback as _createComponentWithFallback, child as _child, setProp as _setProp, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
|
||||||
const t0 = _template("<div :id=\\"foo\\"><Comp></Comp>{{ bar }}</div>")
|
const t0 = _template("<div :id=\\"foo\\"><Comp></Comp>{{ bar }}</div>")
|
||||||
const t1 = _template("<div> </div>")
|
const t1 = _template("<div> </div>")
|
||||||
|
|
||||||
|
@ -161,8 +161,8 @@ export function render(_ctx, $props, $emit, $attrs, $slots) {
|
||||||
_setInsertionState(n3, 0)
|
_setInsertionState(n3, 0)
|
||||||
const n1 = _createComponentWithFallback(_component_Comp)
|
const n1 = _createComponentWithFallback(_component_Comp)
|
||||||
_renderEffect(() => {
|
_renderEffect(() => {
|
||||||
_setText(n2, _toDisplayString(_ctx.bar))
|
|
||||||
_setProp(n3, "id", _ctx.foo)
|
_setProp(n3, "id", _ctx.foo)
|
||||||
|
_setText(n2, _toDisplayString(_ctx.bar))
|
||||||
})
|
})
|
||||||
return [n0, n3]
|
return [n0, n3]
|
||||||
}"
|
}"
|
||||||
|
@ -180,7 +180,7 @@ export function render(_ctx) {
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`compile > dynamic root nodes and interpolation 1`] = `
|
exports[`compile > dynamic root nodes and interpolation 1`] = `
|
||||||
"import { child as _child, toDisplayString as _toDisplayString, setText as _setText, setProp as _setProp, renderEffect as _renderEffect, delegateEvents as _delegateEvents, template as _template } from 'vue';
|
"import { child as _child, setProp as _setProp, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, delegateEvents as _delegateEvents, template as _template } from 'vue';
|
||||||
const t0 = _template("<button> </button>", true)
|
const t0 = _template("<button> </button>", true)
|
||||||
_delegateEvents("click")
|
_delegateEvents("click")
|
||||||
|
|
||||||
|
@ -190,13 +190,47 @@ export function render(_ctx) {
|
||||||
n0.$evtclick = e => _ctx.handleClick(e)
|
n0.$evtclick = e => _ctx.handleClick(e)
|
||||||
_renderEffect(() => {
|
_renderEffect(() => {
|
||||||
const _count = _ctx.count
|
const _count = _ctx.count
|
||||||
_setText(x0, _toDisplayString(_count) + "foo" + _toDisplayString(_count) + "foo" + _toDisplayString(_count))
|
|
||||||
_setProp(n0, "id", _count)
|
_setProp(n0, "id", _count)
|
||||||
|
_setText(x0, _toDisplayString(_count) + "foo" + _toDisplayString(_count) + "foo" + _toDisplayString(_count))
|
||||||
})
|
})
|
||||||
return n0
|
return n0
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`compile > execution order > basic 1`] = `
|
||||||
|
"import { child as _child, setProp as _setProp, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
|
||||||
|
const t0 = _template("<div> </div>", true)
|
||||||
|
|
||||||
|
export function render(_ctx) {
|
||||||
|
const n0 = t0()
|
||||||
|
const x0 = _child(n0)
|
||||||
|
_renderEffect(() => {
|
||||||
|
_setProp(n0, "id", _ctx.foo)
|
||||||
|
_setText(x0, _toDisplayString(_ctx.bar))
|
||||||
|
})
|
||||||
|
return n0
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`compile > execution order > with v-once 1`] = `
|
||||||
|
"import { child as _child, next as _next, nthChild as _nthChild, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
|
||||||
|
const t0 = _template("<div><span> </span> <br> </div>", true)
|
||||||
|
|
||||||
|
export function render(_ctx) {
|
||||||
|
const n3 = t0()
|
||||||
|
const n0 = _child(n3)
|
||||||
|
const n1 = _next(n0)
|
||||||
|
const n2 = _nthChild(n3, 3)
|
||||||
|
const x0 = _child(n0)
|
||||||
|
_setText(x0, _toDisplayString(_ctx.foo))
|
||||||
|
_renderEffect(() => {
|
||||||
|
_setText(n1, " " + _toDisplayString(_ctx.bar))
|
||||||
|
_setText(n2, " " + _toDisplayString(_ctx.baz))
|
||||||
|
})
|
||||||
|
return n3
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`compile > expression parsing > interpolation 1`] = `
|
exports[`compile > expression parsing > interpolation 1`] = `
|
||||||
"
|
"
|
||||||
const n0 = t0()
|
const n0 = t0()
|
||||||
|
|
|
@ -237,4 +237,29 @@ describe('compile', () => {
|
||||||
expect(code).toMatchSnapshot()
|
expect(code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('execution order', () => {
|
||||||
|
test('basic', () => {
|
||||||
|
const code = compile(`<div :id="foo">{{ bar }}</div>`)
|
||||||
|
expect(code).matchSnapshot()
|
||||||
|
expect(code).contains(
|
||||||
|
`_setProp(n0, "id", _ctx.foo)
|
||||||
|
_setText(x0, _toDisplayString(_ctx.bar))`,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
test('with v-once', () => {
|
||||||
|
const code = compile(
|
||||||
|
`<div>
|
||||||
|
<span v-once>{{ foo }}</span>
|
||||||
|
{{ bar }}<br>
|
||||||
|
{{ baz }}
|
||||||
|
</div>`,
|
||||||
|
)
|
||||||
|
expect(code).matchSnapshot()
|
||||||
|
expect(code).contains(
|
||||||
|
`_setText(n1, " " + _toDisplayString(_ctx.bar))
|
||||||
|
_setText(n2, " " + _toDisplayString(_ctx.baz))`,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -67,7 +67,6 @@ export function render(_ctx) {
|
||||||
const x2 = _child(n2)
|
const x2 = _child(n2)
|
||||||
_renderEffect(() => {
|
_renderEffect(() => {
|
||||||
const _msg = _ctx.msg
|
const _msg = _ctx.msg
|
||||||
|
|
||||||
_setText(x0, _toDisplayString(_msg))
|
_setText(x0, _toDisplayString(_msg))
|
||||||
_setText(x1, _toDisplayString(_msg))
|
_setText(x1, _toDisplayString(_msg))
|
||||||
_setText(x2, _toDisplayString(_msg))
|
_setText(x2, _toDisplayString(_msg))
|
||||||
|
|
|
@ -55,7 +55,6 @@ export function render(_ctx) {
|
||||||
const _foo = _ctx.foo
|
const _foo = _ctx.foo
|
||||||
const _bar = _ctx.bar
|
const _bar = _ctx.bar
|
||||||
const _foo_bar_baz = _foo[_bar(_ctx.baz)]
|
const _foo_bar_baz = _foo[_bar(_ctx.baz)]
|
||||||
|
|
||||||
_setProp(n0, "id", _foo_bar_baz)
|
_setProp(n0, "id", _foo_bar_baz)
|
||||||
_setProp(n1, "id", _foo_bar_baz)
|
_setProp(n1, "id", _foo_bar_baz)
|
||||||
_setProp(n2, "id", _bar() + _foo)
|
_setProp(n2, "id", _bar() + _foo)
|
||||||
|
@ -107,7 +106,6 @@ export function render(_ctx) {
|
||||||
_renderEffect(() => {
|
_renderEffect(() => {
|
||||||
const _obj = _ctx.obj
|
const _obj = _ctx.obj
|
||||||
const _obj_foo_baz_obj_bar = _obj['foo']['baz'] + _obj.bar
|
const _obj_foo_baz_obj_bar = _obj['foo']['baz'] + _obj.bar
|
||||||
|
|
||||||
_setProp(n0, "id", _obj_foo_baz_obj_bar)
|
_setProp(n0, "id", _obj_foo_baz_obj_bar)
|
||||||
_setProp(n1, "id", _obj_foo_baz_obj_bar)
|
_setProp(n1, "id", _obj_foo_baz_obj_bar)
|
||||||
})
|
})
|
||||||
|
@ -126,7 +124,6 @@ export function render(_ctx) {
|
||||||
_renderEffect(() => {
|
_renderEffect(() => {
|
||||||
const _foo = _ctx.foo
|
const _foo = _ctx.foo
|
||||||
const _foo_bar = _foo + _ctx.bar
|
const _foo_bar = _foo + _ctx.bar
|
||||||
|
|
||||||
_setProp(n0, "id", _foo_bar)
|
_setProp(n0, "id", _foo_bar)
|
||||||
_setProp(n1, "id", _foo_bar)
|
_setProp(n1, "id", _foo_bar)
|
||||||
_setProp(n2, "id", _foo + _foo_bar)
|
_setProp(n2, "id", _foo + _foo_bar)
|
||||||
|
@ -144,7 +141,6 @@ export function render(_ctx) {
|
||||||
const n1 = t0()
|
const n1 = t0()
|
||||||
_renderEffect(() => {
|
_renderEffect(() => {
|
||||||
const _foo_bar = _ctx.foo + _ctx.bar
|
const _foo_bar = _ctx.foo + _ctx.bar
|
||||||
|
|
||||||
_setProp(n0, "id", _foo_bar)
|
_setProp(n0, "id", _foo_bar)
|
||||||
_setProp(n1, "id", _foo_bar)
|
_setProp(n1, "id", _foo_bar)
|
||||||
})
|
})
|
||||||
|
@ -177,7 +173,6 @@ export function render(_ctx) {
|
||||||
const n1 = t0()
|
const n1 = t0()
|
||||||
_renderEffect(() => {
|
_renderEffect(() => {
|
||||||
const _foo = _ctx.foo
|
const _foo = _ctx.foo
|
||||||
|
|
||||||
_setClass(n0, _foo)
|
_setClass(n0, _foo)
|
||||||
_setClass(n1, _foo)
|
_setClass(n1, _foo)
|
||||||
})
|
})
|
||||||
|
@ -498,15 +493,13 @@ export function render(_ctx) {
|
||||||
_setAttr(n0, "form", _ctx.form)
|
_setAttr(n0, "form", _ctx.form)
|
||||||
_setAttr(n1, "list", _ctx.list)
|
_setAttr(n1, "list", _ctx.list)
|
||||||
_setAttr(n2, "type", _ctx.type)
|
_setAttr(n2, "type", _ctx.type)
|
||||||
|
|
||||||
_setAttr(n3, "width", _width)
|
_setAttr(n3, "width", _width)
|
||||||
_setAttr(n4, "width", _width)
|
|
||||||
_setAttr(n5, "width", _width)
|
|
||||||
_setAttr(n6, "width", _width)
|
|
||||||
|
|
||||||
_setAttr(n3, "height", _height)
|
_setAttr(n3, "height", _height)
|
||||||
|
_setAttr(n4, "width", _width)
|
||||||
_setAttr(n4, "height", _height)
|
_setAttr(n4, "height", _height)
|
||||||
|
_setAttr(n5, "width", _width)
|
||||||
_setAttr(n5, "height", _height)
|
_setAttr(n5, "height", _height)
|
||||||
|
_setAttr(n6, "width", _width)
|
||||||
_setAttr(n6, "height", _height)
|
_setAttr(n6, "height", _height)
|
||||||
})
|
})
|
||||||
return [n0, n1, n2, n3, n4, n5, n6]
|
return [n0, n1, n2, n3, n4, n5, n6]
|
||||||
|
|
|
@ -81,8 +81,8 @@ export function getBaseTransformPreset(): TransformPreset {
|
||||||
transformVFor,
|
transformVFor,
|
||||||
transformSlotOutlet,
|
transformSlotOutlet,
|
||||||
transformTemplateRef,
|
transformTemplateRef,
|
||||||
transformText,
|
|
||||||
transformElement,
|
transformElement,
|
||||||
|
transformText,
|
||||||
transformVSlot,
|
transformVSlot,
|
||||||
transformComment,
|
transformComment,
|
||||||
transformChildren,
|
transformChildren,
|
||||||
|
|
|
@ -99,10 +99,8 @@ export function genEffects(
|
||||||
effects: IREffect[],
|
effects: IREffect[],
|
||||||
context: CodegenContext,
|
context: CodegenContext,
|
||||||
): CodeFragment[] {
|
): CodeFragment[] {
|
||||||
const {
|
const { helper } = context
|
||||||
helper,
|
const expressions = effects.flatMap(effect => effect.expressions)
|
||||||
block: { expressions },
|
|
||||||
} = context
|
|
||||||
const [frag, push, unshift] = buildCodeFragment()
|
const [frag, push, unshift] = buildCodeFragment()
|
||||||
let operationsCount = 0
|
let operationsCount = 0
|
||||||
const { ids, frag: declarationFrags } = processExpressions(
|
const { ids, frag: declarationFrags } = processExpressions(
|
||||||
|
|
|
@ -52,7 +52,6 @@ export interface BlockIRNode extends BaseIRNode {
|
||||||
tempId: number
|
tempId: number
|
||||||
effect: IREffect[]
|
effect: IREffect[]
|
||||||
operation: OperationNode[]
|
operation: OperationNode[]
|
||||||
expressions: SimpleExpressionNode[]
|
|
||||||
returns: number[]
|
returns: number[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -140,8 +140,10 @@ export class TransformContext<T extends AllNode = AllNode> {
|
||||||
|
|
||||||
registerEffect(
|
registerEffect(
|
||||||
expressions: SimpleExpressionNode[],
|
expressions: SimpleExpressionNode[],
|
||||||
...operations: OperationNode[]
|
operation: OperationNode | OperationNode[],
|
||||||
|
getIndex = (): number => this.block.effect.length,
|
||||||
): void {
|
): void {
|
||||||
|
const operations = [operation].flat()
|
||||||
expressions = expressions.filter(exp => !isConstantExpression(exp))
|
expressions = expressions.filter(exp => !isConstantExpression(exp))
|
||||||
if (
|
if (
|
||||||
this.inVOnce ||
|
this.inVOnce ||
|
||||||
|
@ -153,26 +155,10 @@ export class TransformContext<T extends AllNode = AllNode> {
|
||||||
return this.registerOperation(...operations)
|
return this.registerOperation(...operations)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.block.expressions.push(...expressions)
|
this.block.effect.splice(getIndex(), 0, {
|
||||||
const existing = this.block.effect.find(e =>
|
expressions,
|
||||||
isSameExpression(e.expressions, expressions),
|
operations,
|
||||||
)
|
})
|
||||||
if (existing) {
|
|
||||||
existing.operations.push(...operations)
|
|
||||||
} else {
|
|
||||||
this.block.effect.push({
|
|
||||||
expressions,
|
|
||||||
operations,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function isSameExpression(
|
|
||||||
a: SimpleExpressionNode[],
|
|
||||||
b: SimpleExpressionNode[],
|
|
||||||
) {
|
|
||||||
if (a.length !== b.length) return false
|
|
||||||
return a.every((exp, i) => exp.content === b[i].content)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
registerOperation(...node: OperationNode[]): void {
|
registerOperation(...node: OperationNode[]): void {
|
||||||
|
|
|
@ -44,6 +44,8 @@ export const isReservedProp: (key: string) => boolean = /*#__PURE__*/ makeMap(
|
||||||
)
|
)
|
||||||
|
|
||||||
export const transformElement: NodeTransform = (node, context) => {
|
export const transformElement: NodeTransform = (node, context) => {
|
||||||
|
let effectIndex = context.block.effect.length
|
||||||
|
const getEffectIndex = () => effectIndex++
|
||||||
return function postTransformElement() {
|
return function postTransformElement() {
|
||||||
;({ node } = context)
|
;({ node } = context)
|
||||||
if (
|
if (
|
||||||
|
@ -62,6 +64,7 @@ export const transformElement: NodeTransform = (node, context) => {
|
||||||
context as TransformContext<ElementNode>,
|
context as TransformContext<ElementNode>,
|
||||||
isComponent,
|
isComponent,
|
||||||
isDynamicComponent,
|
isDynamicComponent,
|
||||||
|
getEffectIndex,
|
||||||
)
|
)
|
||||||
|
|
||||||
let { parent } = context
|
let { parent } = context
|
||||||
|
@ -78,13 +81,23 @@ export const transformElement: NodeTransform = (node, context) => {
|
||||||
parent.node.children.filter(child => child.type !== NodeTypes.COMMENT)
|
parent.node.children.filter(child => child.type !== NodeTypes.COMMENT)
|
||||||
.length === 1
|
.length === 1
|
||||||
|
|
||||||
;(isComponent ? transformComponentElement : transformNativeElement)(
|
if (isComponent) {
|
||||||
node as any,
|
transformComponentElement(
|
||||||
propsResult,
|
node as ComponentNode,
|
||||||
singleRoot,
|
propsResult,
|
||||||
context as TransformContext<ElementNode>,
|
singleRoot,
|
||||||
isDynamicComponent,
|
context,
|
||||||
)
|
isDynamicComponent,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
transformNativeElement(
|
||||||
|
node as PlainElementNode,
|
||||||
|
propsResult,
|
||||||
|
singleRoot,
|
||||||
|
context,
|
||||||
|
getEffectIndex,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,7 +196,8 @@ function transformNativeElement(
|
||||||
node: PlainElementNode,
|
node: PlainElementNode,
|
||||||
propsResult: PropsResult,
|
propsResult: PropsResult,
|
||||||
singleRoot: boolean,
|
singleRoot: boolean,
|
||||||
context: TransformContext<ElementNode>,
|
context: TransformContext,
|
||||||
|
getEffectIndex: () => number,
|
||||||
) {
|
) {
|
||||||
const { tag } = node
|
const { tag } = node
|
||||||
const { scopeId } = context.options
|
const { scopeId } = context.options
|
||||||
|
@ -196,12 +210,16 @@ function transformNativeElement(
|
||||||
const dynamicProps: string[] = []
|
const dynamicProps: string[] = []
|
||||||
if (propsResult[0] /* dynamic props */) {
|
if (propsResult[0] /* dynamic props */) {
|
||||||
const [, dynamicArgs, expressions] = propsResult
|
const [, dynamicArgs, expressions] = propsResult
|
||||||
context.registerEffect(expressions, {
|
context.registerEffect(
|
||||||
type: IRNodeTypes.SET_DYNAMIC_PROPS,
|
expressions,
|
||||||
element: context.reference(),
|
{
|
||||||
props: dynamicArgs,
|
type: IRNodeTypes.SET_DYNAMIC_PROPS,
|
||||||
root: singleRoot,
|
element: context.reference(),
|
||||||
})
|
props: dynamicArgs,
|
||||||
|
root: singleRoot,
|
||||||
|
},
|
||||||
|
getEffectIndex,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
for (const prop of propsResult[1]) {
|
for (const prop of propsResult[1]) {
|
||||||
const { key, values } = prop
|
const { key, values } = prop
|
||||||
|
@ -210,13 +228,17 @@ function transformNativeElement(
|
||||||
if (values[0].content) template += `="${values[0].content}"`
|
if (values[0].content) template += `="${values[0].content}"`
|
||||||
} else {
|
} else {
|
||||||
dynamicProps.push(key.content)
|
dynamicProps.push(key.content)
|
||||||
context.registerEffect(values, {
|
context.registerEffect(
|
||||||
type: IRNodeTypes.SET_PROP,
|
values,
|
||||||
element: context.reference(),
|
{
|
||||||
prop,
|
type: IRNodeTypes.SET_PROP,
|
||||||
root: singleRoot,
|
element: context.reference(),
|
||||||
tag,
|
prop,
|
||||||
})
|
root: singleRoot,
|
||||||
|
tag,
|
||||||
|
},
|
||||||
|
getEffectIndex,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -253,6 +275,7 @@ export function buildProps(
|
||||||
context: TransformContext<ElementNode>,
|
context: TransformContext<ElementNode>,
|
||||||
isComponent: boolean,
|
isComponent: boolean,
|
||||||
isDynamicComponent?: boolean,
|
isDynamicComponent?: boolean,
|
||||||
|
getEffectIndex?: () => number,
|
||||||
): PropsResult {
|
): PropsResult {
|
||||||
const props = node.props as (VaporDirectiveNode | AttributeNode)[]
|
const props = node.props as (VaporDirectiveNode | AttributeNode)[]
|
||||||
if (props.length === 0) return [false, []]
|
if (props.length === 0) return [false, []]
|
||||||
|
@ -299,12 +322,12 @@ export function buildProps(
|
||||||
} else {
|
} else {
|
||||||
context.registerEffect(
|
context.registerEffect(
|
||||||
[prop.exp],
|
[prop.exp],
|
||||||
|
|
||||||
{
|
{
|
||||||
type: IRNodeTypes.SET_DYNAMIC_EVENTS,
|
type: IRNodeTypes.SET_DYNAMIC_EVENTS,
|
||||||
element: context.reference(),
|
element: context.reference(),
|
||||||
event: prop.exp,
|
event: prop.exp,
|
||||||
},
|
},
|
||||||
|
getEffectIndex,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -29,7 +29,6 @@ export const newBlock = (node: BlockIRNode['node']): BlockIRNode => ({
|
||||||
effect: [],
|
effect: [],
|
||||||
operation: [],
|
operation: [],
|
||||||
returns: [],
|
returns: [],
|
||||||
expressions: [],
|
|
||||||
tempId: 0,
|
tempId: 0,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue