fix(compiler-vapor): adjust children generation order for hydration

This commit is contained in:
daiwei 2025-08-01 15:12:11 +08:00
parent 07fd7e4d41
commit df28fa503b
6 changed files with 35 additions and 14 deletions

View File

@ -212,6 +212,22 @@ export function render(_ctx) {
}"
`;
exports[`compile > execution order > with insertionState 1`] = `
"import { resolveComponent as _resolveComponent, child as _child, setInsertionState as _setInsertionState, createSlot as _createSlot, createComponentWithFallback as _createComponentWithFallback, template as _template } from 'vue';
const t0 = _template("<div><div></div></div>", true)
export function render(_ctx) {
const _component_Comp = _resolveComponent("Comp")
const n3 = t0()
const n1 = _child(n3)
_setInsertionState(n1)
const n0 = _createSlot("default", null)
_setInsertionState(n3)
const n2 = _createComponentWithFallback(_component_Comp)
return n3
}"
`;
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)

View File

@ -247,6 +247,7 @@ describe('compile', () => {
_setText(x0, _toDisplayString(_ctx.bar))`,
)
})
test('with v-once', () => {
const code = compile(
`<div>
@ -261,5 +262,10 @@ describe('compile', () => {
_setText(n2, " " + _toDisplayString(_ctx.baz))`,
)
})
test('with insertionState', () => {
const code = compile(`<div><div><slot /></div><Comp/></div>`)
expect(code).matchSnapshot()
})
})
})

View File

@ -57,10 +57,10 @@ const t0 = _template("<div><div>x</div><div><span> </span></div><div><span> </sp
export function render(_ctx) {
const n3 = t0()
const p0 = _next(_child(n3))
const p1 = _next(p0)
const p2 = _next(p1)
const n0 = _child(p0)
const p1 = _next(p0)
const n1 = _child(p1)
const p2 = _next(p1)
const n2 = _child(p2)
const x0 = _child(n0)
const x1 = _child(n1)

View File

@ -343,8 +343,8 @@ const t2 = _template("<form></form>")
export function render(_ctx) {
const n1 = t1()
const n3 = t2()
const n0 = t0()
const n3 = t2()
const n2 = t2()
_insert(n0, n1)
_insert(n2, n3)

View File

@ -65,7 +65,9 @@ export function genBlockContent(
push(...genSelf(child, context))
}
for (const child of dynamic.children) {
push(...genChildren(child, context, push, `n${child.id!}`))
if (!child.hasDynamicChild) {
push(...genChildren(child, context, push, `n${child.id!}`))
}
}
push(...genOperations(operation, context))

View File

@ -24,7 +24,7 @@ export function genSelf(
context: CodegenContext,
): CodeFragment[] {
const [frag, push] = buildCodeFragment()
const { id, template, operation } = dynamic
const { id, template, operation, hasDynamicChild } = dynamic
if (id !== undefined && template !== undefined) {
push(NEWLINE, `const n${id} = t${template}()`)
@ -35,6 +35,10 @@ export function genSelf(
push(...genOperationWithInsertionState(operation, context))
}
if (hasDynamicChild) {
push(...genChildren(dynamic, context, push, `n${id}`))
}
return frag
}
@ -50,7 +54,6 @@ export function genChildren(
let offset = 0
let prev: [variable: string, elementIndex: number] | undefined
const childrenToGen: [IRDynamicInfo, string][] = []
for (const [index, child] of children.entries()) {
if (child.flags & DynamicFlag.NON_TEMPLATE) {
@ -96,7 +99,7 @@ export function genChildren(
}
}
if (id === child.anchor) {
if (id === child.anchor && !child.hasDynamicChild) {
push(...genSelf(child, context))
}
@ -105,13 +108,7 @@ export function genChildren(
}
prev = [variable, elementIndex]
childrenToGen.push([child, variable])
}
if (childrenToGen.length) {
for (const [child, from] of childrenToGen) {
push(...genChildren(child, context, pushBlock, from))
}
push(...genChildren(child, context, pushBlock, variable))
}
return frag