Skip to content

Commit bf7424a

Browse files
authored
fix(compiler-vapor): correct execution order of operations (#13351)
1 parent 430216a commit bf7424a

File tree

10 files changed

+121
-65
lines changed

10 files changed

+121
-65
lines changed

packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ export function render(_ctx, $props, $emit, $attrs, $slots) {
149149
`;
150150
151151
exports[`compile > directives > v-pre > should not affect siblings after it 1`] = `
152-
"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';
152+
"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';
153153
const t0 = _template("<div :id=\\"foo\\"><Comp></Comp>{{ bar }}</div>")
154154
const t1 = _template("<div> </div>")
155155
@@ -161,8 +161,8 @@ export function render(_ctx, $props, $emit, $attrs, $slots) {
161161
_setInsertionState(n3, 0)
162162
const n1 = _createComponentWithFallback(_component_Comp)
163163
_renderEffect(() => {
164-
_setText(n2, _toDisplayString(_ctx.bar))
165164
_setProp(n3, "id", _ctx.foo)
165+
_setText(n2, _toDisplayString(_ctx.bar))
166166
})
167167
return [n0, n3]
168168
}"
@@ -180,7 +180,7 @@ export function render(_ctx) {
180180
`;
181181
182182
exports[`compile > dynamic root nodes and interpolation 1`] = `
183-
"import { child as _child, toDisplayString as _toDisplayString, setText as _setText, setProp as _setProp, renderEffect as _renderEffect, delegateEvents as _delegateEvents, template as _template } from 'vue';
183+
"import { child as _child, setProp as _setProp, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, delegateEvents as _delegateEvents, template as _template } from 'vue';
184184
const t0 = _template("<button> </button>", true)
185185
_delegateEvents("click")
186186
@@ -190,13 +190,47 @@ export function render(_ctx) {
190190
n0.$evtclick = e => _ctx.handleClick(e)
191191
_renderEffect(() => {
192192
const _count = _ctx.count
193-
_setText(x0, _toDisplayString(_count) + "foo" + _toDisplayString(_count) + "foo" + _toDisplayString(_count))
194193
_setProp(n0, "id", _count)
194+
_setText(x0, _toDisplayString(_count) + "foo" + _toDisplayString(_count) + "foo" + _toDisplayString(_count))
195195
})
196196
return n0
197197
}"
198198
`;
199199
200+
exports[`compile > execution order > basic 1`] = `
201+
"import { child as _child, setProp as _setProp, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
202+
const t0 = _template("<div> </div>", true)
203+
204+
export function render(_ctx) {
205+
const n0 = t0()
206+
const x0 = _child(n0)
207+
_renderEffect(() => {
208+
_setProp(n0, "id", _ctx.foo)
209+
_setText(x0, _toDisplayString(_ctx.bar))
210+
})
211+
return n0
212+
}"
213+
`;
214+
215+
exports[`compile > execution order > with v-once 1`] = `
216+
"import { child as _child, next as _next, nthChild as _nthChild, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
217+
const t0 = _template("<div><span> </span> <br> </div>", true)
218+
219+
export function render(_ctx) {
220+
const n3 = t0()
221+
const n0 = _child(n3)
222+
const n1 = _next(n0)
223+
const n2 = _nthChild(n3, 3)
224+
const x0 = _child(n0)
225+
_setText(x0, _toDisplayString(_ctx.foo))
226+
_renderEffect(() => {
227+
_setText(n1, " " + _toDisplayString(_ctx.bar))
228+
_setText(n2, " " + _toDisplayString(_ctx.baz))
229+
})
230+
return n3
231+
}"
232+
`;
233+
200234
exports[`compile > expression parsing > interpolation 1`] = `
201235
"
202236
const n0 = t0()

packages/compiler-vapor/__tests__/compile.spec.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,4 +237,29 @@ describe('compile', () => {
237237
expect(code).toMatchSnapshot()
238238
})
239239
})
240+
241+
describe('execution order', () => {
242+
test('basic', () => {
243+
const code = compile(`<div :id="foo">{{ bar }}</div>`)
244+
expect(code).matchSnapshot()
245+
expect(code).contains(
246+
`_setProp(n0, "id", _ctx.foo)
247+
_setText(x0, _toDisplayString(_ctx.bar))`,
248+
)
249+
})
250+
test('with v-once', () => {
251+
const code = compile(
252+
`<div>
253+
<span v-once>{{ foo }}</span>
254+
{{ bar }}<br>
255+
{{ baz }}
256+
</div>`,
257+
)
258+
expect(code).matchSnapshot()
259+
expect(code).contains(
260+
`_setText(n1, " " + _toDisplayString(_ctx.bar))
261+
_setText(n2, " " + _toDisplayString(_ctx.baz))`,
262+
)
263+
})
264+
})
240265
})

packages/compiler-vapor/__tests__/transforms/__snapshots__/transformChildren.spec.ts.snap

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ export function render(_ctx) {
6767
const x2 = _child(n2)
6868
_renderEffect(() => {
6969
const _msg = _ctx.msg
70-
7170
_setText(x0, _toDisplayString(_msg))
7271
_setText(x1, _toDisplayString(_msg))
7372
_setText(x2, _toDisplayString(_msg))

packages/compiler-vapor/__tests__/transforms/__snapshots__/vBind.spec.ts.snap

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ export function render(_ctx) {
5555
const _foo = _ctx.foo
5656
const _bar = _ctx.bar
5757
const _foo_bar_baz = _foo[_bar(_ctx.baz)]
58-
5958
_setProp(n0, "id", _foo_bar_baz)
6059
_setProp(n1, "id", _foo_bar_baz)
6160
_setProp(n2, "id", _bar() + _foo)
@@ -107,7 +106,6 @@ export function render(_ctx) {
107106
_renderEffect(() => {
108107
const _obj = _ctx.obj
109108
const _obj_foo_baz_obj_bar = _obj['foo']['baz'] + _obj.bar
110-
111109
_setProp(n0, "id", _obj_foo_baz_obj_bar)
112110
_setProp(n1, "id", _obj_foo_baz_obj_bar)
113111
})
@@ -126,7 +124,6 @@ export function render(_ctx) {
126124
_renderEffect(() => {
127125
const _foo = _ctx.foo
128126
const _foo_bar = _foo + _ctx.bar
129-
130127
_setProp(n0, "id", _foo_bar)
131128
_setProp(n1, "id", _foo_bar)
132129
_setProp(n2, "id", _foo + _foo_bar)
@@ -144,7 +141,6 @@ export function render(_ctx) {
144141
const n1 = t0()
145142
_renderEffect(() => {
146143
const _foo_bar = _ctx.foo + _ctx.bar
147-
148144
_setProp(n0, "id", _foo_bar)
149145
_setProp(n1, "id", _foo_bar)
150146
})
@@ -177,7 +173,6 @@ export function render(_ctx) {
177173
const n1 = t0()
178174
_renderEffect(() => {
179175
const _foo = _ctx.foo
180-
181176
_setClass(n0, _foo)
182177
_setClass(n1, _foo)
183178
})
@@ -498,15 +493,13 @@ export function render(_ctx) {
498493
_setAttr(n0, "form", _ctx.form)
499494
_setAttr(n1, "list", _ctx.list)
500495
_setAttr(n2, "type", _ctx.type)
501-
502496
_setAttr(n3, "width", _width)
503-
_setAttr(n4, "width", _width)
504-
_setAttr(n5, "width", _width)
505-
_setAttr(n6, "width", _width)
506-
507497
_setAttr(n3, "height", _height)
498+
_setAttr(n4, "width", _width)
508499
_setAttr(n4, "height", _height)
500+
_setAttr(n5, "width", _width)
509501
_setAttr(n5, "height", _height)
502+
_setAttr(n6, "width", _width)
510503
_setAttr(n6, "height", _height)
511504
})
512505
return [n0, n1, n2, n3, n4, n5, n6]

packages/compiler-vapor/src/compile.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@ export function getBaseTransformPreset(): TransformPreset {
8181
transformVFor,
8282
transformSlotOutlet,
8383
transformTemplateRef,
84-
transformText,
8584
transformElement,
85+
transformText,
8686
transformVSlot,
8787
transformComment,
8888
transformChildren,

packages/compiler-vapor/src/generators/operation.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,8 @@ export function genEffects(
9999
effects: IREffect[],
100100
context: CodegenContext,
101101
): CodeFragment[] {
102-
const {
103-
helper,
104-
block: { expressions },
105-
} = context
102+
const { helper } = context
103+
const expressions = effects.flatMap(effect => effect.expressions)
106104
const [frag, push, unshift] = buildCodeFragment()
107105
let operationsCount = 0
108106
const { ids, frag: declarationFrags } = processExpressions(

packages/compiler-vapor/src/ir/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ export interface BlockIRNode extends BaseIRNode {
5252
tempId: number
5353
effect: IREffect[]
5454
operation: OperationNode[]
55-
expressions: SimpleExpressionNode[]
5655
returns: number[]
5756
}
5857

packages/compiler-vapor/src/transform.ts

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,10 @@ export class TransformContext<T extends AllNode = AllNode> {
140140

141141
registerEffect(
142142
expressions: SimpleExpressionNode[],
143-
...operations: OperationNode[]
143+
operation: OperationNode | OperationNode[],
144+
getIndex = (): number => this.block.effect.length,
144145
): void {
146+
const operations = [operation].flat()
145147
expressions = expressions.filter(exp => !isConstantExpression(exp))
146148
if (
147149
this.inVOnce ||
@@ -153,26 +155,10 @@ export class TransformContext<T extends AllNode = AllNode> {
153155
return this.registerOperation(...operations)
154156
}
155157

156-
this.block.expressions.push(...expressions)
157-
const existing = this.block.effect.find(e =>
158-
isSameExpression(e.expressions, expressions),
159-
)
160-
if (existing) {
161-
existing.operations.push(...operations)
162-
} else {
163-
this.block.effect.push({
164-
expressions,
165-
operations,
166-
})
167-
}
168-
169-
function isSameExpression(
170-
a: SimpleExpressionNode[],
171-
b: SimpleExpressionNode[],
172-
) {
173-
if (a.length !== b.length) return false
174-
return a.every((exp, i) => exp.content === b[i].content)
175-
}
158+
this.block.effect.splice(getIndex(), 0, {
159+
expressions,
160+
operations,
161+
})
176162
}
177163

178164
registerOperation(...node: OperationNode[]): void {

packages/compiler-vapor/src/transforms/transformElement.ts

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ export const isReservedProp: (key: string) => boolean = /*#__PURE__*/ makeMap(
4444
)
4545

4646
export const transformElement: NodeTransform = (node, context) => {
47+
let effectIndex = context.block.effect.length
48+
const getEffectIndex = () => effectIndex++
4749
return function postTransformElement() {
4850
;({ node } = context)
4951
if (
@@ -62,6 +64,7 @@ export const transformElement: NodeTransform = (node, context) => {
6264
context as TransformContext<ElementNode>,
6365
isComponent,
6466
isDynamicComponent,
67+
getEffectIndex,
6568
)
6669

6770
let { parent } = context
@@ -78,13 +81,23 @@ export const transformElement: NodeTransform = (node, context) => {
7881
parent.node.children.filter(child => child.type !== NodeTypes.COMMENT)
7982
.length === 1
8083

81-
;(isComponent ? transformComponentElement : transformNativeElement)(
82-
node as any,
83-
propsResult,
84-
singleRoot,
85-
context as TransformContext<ElementNode>,
86-
isDynamicComponent,
87-
)
84+
if (isComponent) {
85+
transformComponentElement(
86+
node as ComponentNode,
87+
propsResult,
88+
singleRoot,
89+
context,
90+
isDynamicComponent,
91+
)
92+
} else {
93+
transformNativeElement(
94+
node as PlainElementNode,
95+
propsResult,
96+
singleRoot,
97+
context,
98+
getEffectIndex,
99+
)
100+
}
88101
}
89102
}
90103

@@ -183,7 +196,8 @@ function transformNativeElement(
183196
node: PlainElementNode,
184197
propsResult: PropsResult,
185198
singleRoot: boolean,
186-
context: TransformContext<ElementNode>,
199+
context: TransformContext,
200+
getEffectIndex: () => number,
187201
) {
188202
const { tag } = node
189203
const { scopeId } = context.options
@@ -196,12 +210,16 @@ function transformNativeElement(
196210
const dynamicProps: string[] = []
197211
if (propsResult[0] /* dynamic props */) {
198212
const [, dynamicArgs, expressions] = propsResult
199-
context.registerEffect(expressions, {
200-
type: IRNodeTypes.SET_DYNAMIC_PROPS,
201-
element: context.reference(),
202-
props: dynamicArgs,
203-
root: singleRoot,
204-
})
213+
context.registerEffect(
214+
expressions,
215+
{
216+
type: IRNodeTypes.SET_DYNAMIC_PROPS,
217+
element: context.reference(),
218+
props: dynamicArgs,
219+
root: singleRoot,
220+
},
221+
getEffectIndex,
222+
)
205223
} else {
206224
for (const prop of propsResult[1]) {
207225
const { key, values } = prop
@@ -210,13 +228,17 @@ function transformNativeElement(
210228
if (values[0].content) template += `="${values[0].content}"`
211229
} else {
212230
dynamicProps.push(key.content)
213-
context.registerEffect(values, {
214-
type: IRNodeTypes.SET_PROP,
215-
element: context.reference(),
216-
prop,
217-
root: singleRoot,
218-
tag,
219-
})
231+
context.registerEffect(
232+
values,
233+
{
234+
type: IRNodeTypes.SET_PROP,
235+
element: context.reference(),
236+
prop,
237+
root: singleRoot,
238+
tag,
239+
},
240+
getEffectIndex,
241+
)
220242
}
221243
}
222244
}
@@ -253,6 +275,7 @@ export function buildProps(
253275
context: TransformContext<ElementNode>,
254276
isComponent: boolean,
255277
isDynamicComponent?: boolean,
278+
getEffectIndex?: () => number,
256279
): PropsResult {
257280
const props = node.props as (VaporDirectiveNode | AttributeNode)[]
258281
if (props.length === 0) return [false, []]
@@ -299,12 +322,12 @@ export function buildProps(
299322
} else {
300323
context.registerEffect(
301324
[prop.exp],
302-
303325
{
304326
type: IRNodeTypes.SET_DYNAMIC_EVENTS,
305327
element: context.reference(),
306328
event: prop.exp,
307329
},
330+
getEffectIndex,
308331
)
309332
}
310333
} else {

packages/compiler-vapor/src/transforms/utils.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ export const newBlock = (node: BlockIRNode['node']): BlockIRNode => ({
2929
effect: [],
3030
operation: [],
3131
returns: [],
32-
expressions: [],
3332
tempId: 0,
3433
})
3534

0 commit comments

Comments
 (0)