Skip to content

Commit 1fe86e4

Browse files
committed
refactor: add hydration hints
1 parent 735f640 commit 1fe86e4

File tree

19 files changed

+251
-272
lines changed

19 files changed

+251
-272
lines changed

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

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,9 @@ export function render(_ctx, $props, $emit, $attrs, $slots) {
157157
const _component_Comp = _resolveComponent("Comp")
158158
const n0 = t0()
159159
const n3 = t1()
160+
const n2 = _child(n3, 1)
160161
_setInsertionState(n3, 0)
161162
const n1 = _createComponentWithFallback(_component_Comp)
162-
const n2 = _child(n3)
163163
_renderEffect(() => {
164164
_setProp(n3, "id", _ctx.foo)
165165
_setText(n2, _toDisplayString(_ctx.bar))
@@ -212,14 +212,38 @@ export function render(_ctx) {
212212
}"
213213
`;
214214
215+
exports[`compile > execution order > setInsertionState > next, child and nthChild should be above the setInsertionState 1`] = `
216+
"import { resolveComponent as _resolveComponent, nthChild as _nthChild, setInsertionState as _setInsertionState, createComponentWithFallback as _createComponentWithFallback, createIf as _createIf, next as _next, child as _child, setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue';
217+
const t0 = _template("<div></div>")
218+
const t1 = _template("<div><div></div><!><div></div><!><div><button></button></div></div>", true)
219+
220+
export function render(_ctx) {
221+
const _component_Comp = _resolveComponent("Comp")
222+
const n6 = t1()
223+
const n5 = _nthChild(n6, 1, 1)
224+
const n7 = _nthChild(n6, 3, 3)
225+
const p0 = _next(n7, 4)
226+
const n4 = _child(p0, 0)
227+
_setInsertionState(n6, n5)
228+
const n0 = _createComponentWithFallback(_component_Comp)
229+
_setInsertionState(n6, n7)
230+
const n1 = _createIf(() => (true), () => {
231+
const n3 = t0()
232+
return n3
233+
})
234+
_renderEffect(() => _setProp(n4, "disabled", _ctx.foo))
235+
return n6
236+
}"
237+
`;
238+
215239
exports[`compile > execution order > with insertionState 1`] = `
216240
"import { resolveComponent as _resolveComponent, child as _child, setInsertionState as _setInsertionState, createSlot as _createSlot, createComponentWithFallback as _createComponentWithFallback, template as _template } from 'vue';
217241
const t0 = _template("<div><div></div></div>", true)
218242
219243
export function render(_ctx) {
220244
const _component_Comp = _resolveComponent("Comp")
221245
const n3 = t0()
222-
const n1 = _child(n3)
246+
const n1 = _child(n3, 0)
223247
_setInsertionState(n1, null)
224248
const n0 = _createSlot("default", null)
225249
_setInsertionState(n3, 1)
@@ -234,9 +258,9 @@ const t0 = _template("<div><span> </span> <br> </div>", true)
234258
235259
export function render(_ctx) {
236260
const n3 = t0()
237-
const n0 = _child(n3)
238-
const n1 = _next(n0)
239-
const n2 = _nthChild(n3, 3)
261+
const n0 = _child(n3, 0)
262+
const n1 = _next(n0, 1)
263+
const n2 = _nthChild(n3, 3, 3)
240264
const x0 = _txt(n0)
241265
_setText(x0, _toDisplayString(_ctx.foo))
242266
_renderEffect(() => {

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,23 @@ describe('compile', () => {
231231
)
232232
})
233233

234+
describe('setInsertionState', () => {
235+
test('next, child and nthChild should be above the setInsertionState', () => {
236+
const code = compile(`
237+
<div>
238+
<div />
239+
<Comp />
240+
<div />
241+
<div v-if="true" />
242+
<div>
243+
<button :disabled="foo" />
244+
</div>
245+
</div>
246+
`)
247+
expect(code).toMatchSnapshot()
248+
})
249+
})
250+
234251
test('with v-once', () => {
235252
const code = compile(
236253
`<div>

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ const t0 = _template("<div> </div>", true)
4747
4848
export function render(_ctx) {
4949
const n1 = t0()
50-
const n0 = _child(n1)
50+
const n0 = _child(n1, 0)
5151
const x1 = _txt(n1)
5252
_renderEffect(() => {
5353
const _foo = _ctx.foo
@@ -86,7 +86,7 @@ const t0 = _template("<div> </div>", true)
8686
8787
export function render(_ctx) {
8888
const n1 = t0()
89-
const n0 = _child(n1)
89+
const n0 = _child(n1, 0)
9090
const x1 = _txt(n1)
9191
_renderEffect(() => {
9292
const _String = String

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

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
22

33
exports[`compiler: children transform > anchor insertion in middle 1`] = `
4-
"import { child as _child, next as _next, setInsertionState as _setInsertionState, createIf as _createIf, template as _template } from 'vue';
4+
"import { nthChild as _nthChild, setInsertionState as _setInsertionState, createIf as _createIf, template as _template } from 'vue';
55
const t0 = _template("<div></div>")
66
const t1 = _template("<div><div></div><!><div></div></div>", true)
77
88
export function render(_ctx) {
99
const n4 = t1()
10-
const n3 = _next(_child(n4))
10+
const n3 = _nthChild(n4, 1, 1)
1111
_setInsertionState(n4, n3)
1212
const n0 = _createIf(() => (1), () => {
1313
const n2 = t0()
@@ -23,9 +23,9 @@ const t0 = _template("<div><p> </p> <p> </p></div>", true)
2323
2424
export function render(_ctx) {
2525
const n3 = t0()
26-
const n0 = _child(n3)
27-
const n1 = _next(n0)
28-
const n2 = _next(n1)
26+
const n0 = _child(n3, 0)
27+
const n1 = _next(n0, 1)
28+
const n2 = _next(n1, 2)
2929
const x0 = _txt(n0)
3030
const x2 = _txt(n2)
3131
_renderEffect(() => {
@@ -38,30 +38,30 @@ export function render(_ctx) {
3838
`;
3939

4040
exports[`compiler: children transform > efficient find 1`] = `
41-
"import { child as _child, nthChild as _nthChild, txt as _txt, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
41+
"import { nthChild as _nthChild, txt as _txt, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
4242
const t0 = _template("<div><div>x</div><div>x</div><div> </div></div>", true)
4343
4444
export function render(_ctx) {
4545
const n1 = t0()
46-
const n0 = _nthChild(n1, 2)
46+
const n0 = _nthChild(n1, 2, 2)
4747
const x0 = _txt(n0)
4848
_renderEffect(() => _setText(x0, _toDisplayString(_ctx.msg)))
4949
return n1
5050
}"
5151
`;
5252

5353
exports[`compiler: children transform > efficient traversal 1`] = `
54-
"import { child as _child, next as _next, txt as _txt, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
54+
"import { nthChild as _nthChild, child as _child, next as _next, txt as _txt, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
5555
const t0 = _template("<div><div>x</div><div><span> </span></div><div><span> </span></div><div><span> </span></div></div>", true)
5656
5757
export function render(_ctx) {
5858
const n3 = t0()
59-
const p0 = _next(_child(n3))
60-
const n0 = _child(p0)
61-
const p1 = _next(p0)
62-
const n1 = _child(p1)
63-
const p2 = _next(p1)
64-
const n2 = _child(p2)
59+
const p0 = _nthChild(n3, 1, 1)
60+
const n0 = _child(p0, 0)
61+
const p1 = _next(p0, 2)
62+
const n1 = _child(p1, 0)
63+
const p2 = _next(p1, 3)
64+
const n2 = _child(p2, 0)
6565
const x0 = _txt(n0)
6666
const x1 = _txt(n1)
6767
const x2 = _txt(n2)

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ export function render(_ctx) {
243243
const _component_Comp = _resolveComponent("Comp")
244244
const n0 = _createFor(() => (_ctx.list), (_for_item0) => {
245245
const n3 = _createComponentWithFallback(_component_Comp)
246-
const n2 = _child(n3)
246+
const n2 = _child(n3, 0)
247247
_renderEffect(() => _setText(n2, _toDisplayString(_for_item0.value)))
248248
return [n2, n3]
249249
}, undefined, 2)
@@ -259,7 +259,7 @@ export function render(_ctx) {
259259
const _component_Comp = _resolveComponent("Comp")
260260
const n0 = _createFor(() => (_ctx.list), (_for_item0) => {
261261
const n3 = _createComponentWithFallback(_component_Comp)
262-
const n2 = _child(n3)
262+
const n2 = _child(n3, 0)
263263
_renderEffect(() => _setText(n2, _toDisplayString(_for_item0.value)))
264264
return [n2, n3]
265265
}, undefined, 2)

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ const t0 = _template("<div> <span></span></div>", true)
1717
1818
export function render(_ctx, $props, $emit, $attrs, $slots) {
1919
const n2 = t0()
20-
const n0 = _child(n2)
21-
const n1 = _next(n0)
20+
const n0 = _child(n2, 0)
21+
const n1 = _next(n0, 1)
2222
_setText(n0, _toDisplayString(_ctx.msg) + " ")
2323
_setClass(n1, _ctx.clz)
2424
return n2
@@ -54,7 +54,7 @@ const t0 = _template("<div><div></div></div>", true)
5454
5555
export function render(_ctx) {
5656
const n1 = t0()
57-
const n0 = _child(n1)
57+
const n0 = _child(n1, 0)
5858
_setProp(n0, "id", _ctx.foo)
5959
return n1
6060
}"

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ describe('compiler: children transform', () => {
5656
<div>{{ msg }}</div>
5757
</div>`,
5858
)
59-
expect(code).contains(`const n0 = _nthChild(n1, 2)`)
59+
expect(code).contains(`const n0 = _nthChild(n1, 2, 2)`)
6060
expect(code).toMatchSnapshot()
6161
})
6262

@@ -69,7 +69,7 @@ describe('compiler: children transform', () => {
6969
</div>`,
7070
)
7171
// ensure the insertion anchor is generated before the insertion statement
72-
expect(code).toMatch(`const n3 = _next(_child(n4))`)
72+
expect(code).toMatch(`const n3 = _nthChild(n4, 1, 1)`)
7373
expect(code).toMatch(`_setInsertionState(n4, n3)`)
7474
expect(code).toMatchSnapshot()
7575
})

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export function genBlockContent(
7171
}
7272
for (const child of dynamic.children) {
7373
if (!child.hasDynamicChild) {
74-
push(...genChildren(child, context, `n${child.id!}`))
74+
push(...genChildren(child, context, push, `n${child.id!}`))
7575
}
7676
}
7777

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

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import type { CodegenContext } from '../generate'
2-
import { DynamicFlag, type IRDynamicInfo } from '../ir'
2+
import {
3+
DynamicFlag,
4+
type IRDynamicInfo,
5+
type InsertionStateTypes,
6+
} from '../ir'
37
import { genDirectivesForElement } from './directive'
48
import { genOperationWithInsertionState } from './operation'
59
import { type CodeFragment, NEWLINE, buildCodeFragment, genCall } from './utils'
@@ -36,7 +40,7 @@ export function genSelf(
3640
}
3741

3842
if (hasDynamicChild) {
39-
push(...genChildren(dynamic, context, `n${id}`))
43+
push(...genChildren(dynamic, context, push, `n${id}`))
4044
}
4145

4246
return frag
@@ -45,6 +49,7 @@ export function genSelf(
4549
export function genChildren(
4650
dynamic: IRDynamicInfo,
4751
context: CodegenContext,
52+
pushBlock: (...items: CodeFragment[]) => number,
4853
from: string = `n${dynamic.id}`,
4954
): CodeFragment[] {
5055
const { helper } = context
@@ -53,10 +58,19 @@ export function genChildren(
5358

5459
let offset = 0
5560
let prev: [variable: string, elementIndex: number] | undefined
61+
let ifBranchCount = 0
62+
let prependCount = 0
5663

5764
for (const [index, child] of children.entries()) {
65+
if (child.ifBranch) ifBranchCount++
66+
if (
67+
child.operation &&
68+
(child.operation as InsertionStateTypes).anchor === -1
69+
) {
70+
prependCount++
71+
}
5872
if (child.flags & DynamicFlag.NON_TEMPLATE) {
59-
offset--
73+
if (!child.ifBranch) offset--
6074
}
6175

6276
const id =
@@ -72,29 +86,36 @@ export function genChildren(
7286
}
7387

7488
const elementIndex = index + offset
89+
const logicalIndex = elementIndex - ifBranchCount + prependCount
7590
// p for "placeholder" variables that are meant for possible reuse by
7691
// other access paths
7792
const variable = id === undefined ? `p${context.block.tempId++}` : `n${id}`
78-
push(NEWLINE, `const ${variable} = `)
79-
93+
pushBlock(NEWLINE, `const ${variable} = `)
8094
if (prev) {
8195
if (elementIndex - prev[1] === 1) {
82-
push(...genCall(helper('next'), prev[0]))
96+
pushBlock(...genCall(helper('next'), prev[0], String(logicalIndex)))
8397
} else {
84-
push(...genCall(helper('nthChild'), from, String(elementIndex)))
98+
pushBlock(
99+
...genCall(
100+
helper('nthChild'),
101+
from,
102+
String(elementIndex),
103+
String(logicalIndex),
104+
),
105+
)
85106
}
86107
} else {
87108
if (elementIndex === 0) {
88-
push(...genCall(helper('child'), from))
109+
pushBlock(...genCall(helper('child'), from, String(logicalIndex)))
89110
} else {
90-
// check if there's a node that we can reuse from
91-
let init = genCall(helper('child'), from)
92-
if (elementIndex === 1) {
93-
init = genCall(helper('next'), init)
94-
} else if (elementIndex > 1) {
95-
init = genCall(helper('nthChild'), from, String(elementIndex))
96-
}
97-
push(...init)
111+
pushBlock(
112+
...genCall(
113+
helper('nthChild'),
114+
from,
115+
String(elementIndex),
116+
String(logicalIndex),
117+
),
118+
)
98119
}
99120
}
100121

@@ -107,7 +128,7 @@ export function genChildren(
107128
}
108129

109130
prev = [variable, elementIndex]
110-
push(...genChildren(child, context, variable))
131+
push(...genChildren(child, context, pushBlock, variable))
111132
}
112133

113134
return frag

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ export interface IRDynamicInfo {
272272
hasDynamicChild?: boolean
273273
operation?: OperationNode
274274
needsKey?: boolean
275+
ifBranch?: boolean
275276
}
276277

277278
export interface IREffect {

0 commit comments

Comments
 (0)