"default": () => {
const n0 = _createIf(() => (true), () => {
const n3 = t0()
- _setInsertionState(n3, null)
+ _setInsertionState(n3, null, true)
const n2 = _createComponentWithFallback(_component_Bar)
_withVaporDirectives(n2, [[_directive_hello, void 0, void 0, { world: true }]])
return n3
const n0 = t0()
const n3 = t1()
const n2 = _child(n3, 1)
- _setInsertionState(n3, 0)
+ _setInsertionState(n3, 0, true)
const n1 = _createComponentWithFallback(_component_Comp)
_renderEffect(() => {
_setProp(n3, "id", _ctx.foo)
const n4 = _child(p0, 0)
_setInsertionState(n6, n5)
const n0 = _createComponentWithFallback(_component_Comp)
- _setInsertionState(n6, n7)
+ _setInsertionState(n6, n7, true)
const n1 = _createIf(() => (true), () => {
const n3 = t0()
return n3
const _component_Comp = _resolveComponent("Comp")
const n3 = t0()
const n1 = _child(n3, 0)
- _setInsertionState(n1, null)
+ _setInsertionState(n1, null, true)
const n0 = _createSlot("default", null)
- _setInsertionState(n3, 1)
+ _setInsertionState(n3, 1, true)
const n2 = _createComponentWithFallback(_component_Comp)
return n3
}"
return n5
}, () => {
const n14 = t2()
- _setInsertionState(n14, 0)
+ _setInsertionState(n14, 0, true)
const n9 = _createIf(() => (_ctx.c), () => {
const n11 = t1()
return n11
export function render(_ctx) {
const n4 = t1()
const n3 = _next(_child(n4), 1)
- _setInsertionState(n4, n3)
+ _setInsertionState(n4, n3, true)
const n0 = _createIf(() => (1), () => {
const n2 = t0()
return n2
export function render(_ctx) {
const n0 = _createFor(() => (_ctx.list), (_for_item0) => {
const n5 = t1()
- _setInsertionState(n5, null)
+ _setInsertionState(n5, null, true)
const n2 = _createFor(() => (_for_item0.value), (_for_item1) => {
const n4 = t0()
const x4 = _txt(n4)
const n2 = t0()
return n2
})
- _setInsertionState(n8, null)
+ _setInsertionState(n8, null, true)
const n3 = _createIf(() => (_ctx.bar), () => {
const n5 = t1()
return n5
export function render(_ctx) {
const _component_Comp = _resolveComponent("Comp")
const n1 = t0()
- _setInsertionState(n1, null)
+ _setInsertionState(n1, null, true)
const n0 = _createComponentWithFallback(_component_Comp, { id: () => (_ctx.foo) }, null, null, true)
return n1
}"
const n6 = t0()
_setInsertionState(n6, null)
const n0 = _createSlot("foo", null)
- _setInsertionState(n6, null)
+ _setInsertionState(n6, null, true)
const n1 = _createIf(() => (true), () => {
const n3 = _createComponentWithFallback(_component_Foo)
return n3
)
// ensure the insertion anchor is generated before the insertion statement
expect(code).toMatch(`const n3 = _next(_child(n4), 1)`)
- expect(code).toMatch(`_setInsertionState(n4, n3)`)
+ expect(code).toMatch(`_setInsertionState(n4, n3, true)`)
expect(code).toMatchSnapshot()
})
})
operation: InsertionStateTypes,
context: CodegenContext,
): CodeFragment[] {
- const { parent, anchor, append } = operation
+ const { parent, anchor, append, last } = operation
return [
NEWLINE,
...genCall(
? 'null'
: `${anchor}`
: `n${anchor}`,
+ last && 'true',
),
]
}
parent?: number
anchor?: number
append?: boolean
+ last?: boolean
}
export interface IRFor {
parent?: number
anchor?: number
append?: boolean
+ last?: boolean
}
export interface SetPropIRNode extends BaseIRNode {
parent?: number
anchor?: number
append?: boolean
+ last?: boolean
+
scopeId?: string | null
}
parent?: number
anchor?: number
append?: boolean
+ last?: boolean
}
export interface GetTextChildIRNode extends BaseIRNode {
DynamicFlag,
type IRDynamicInfo,
IRNodeTypes,
+ type InsertionStateTypes,
isBlockOperation,
} from '../ir'
let prevDynamics: IRDynamicInfo[] = []
let staticCount = 0
let dynamicCount = 0
+ let lastInsertionChild: IRDynamicInfo | undefined
const children = context.dynamic.children
for (const [index, child] of children.entries()) {
if (child.flags & DynamicFlag.INSERT) {
- prevDynamics.push(child)
+ prevDynamics.push((lastInsertionChild = child))
}
if (!(child.flags & DynamicFlag.NON_TEMPLATE)) {
}
if (prevDynamics.length) {
- registerInsertion(prevDynamics, context, dynamicCount + staticCount, true)
+ registerInsertion(
+ prevDynamics,
+ context,
+ // the logical index of append child
+ dynamicCount + staticCount,
+ true,
+ )
+ }
+
+ if (lastInsertionChild && lastInsertionChild.operation) {
+ ;(lastInsertionChild.operation! as InsertionStateTypes).last = true
}
}
import {
insertionAnchor,
insertionParent,
+ isLastInsertion,
resetInsertionState,
} from './insertionState'
import { advanceHydrationNode, isHydrating } from './dom/hydration'
): VaporFragment {
const _insertionParent = insertionParent
const _insertionAnchor = insertionAnchor
+ const _isLastInsertion = isLastInsertion
if (!isHydrating) resetInsertionState()
const frag =
if (!isHydrating) {
if (_insertionParent) insert(frag, _insertionParent, _insertionAnchor)
} else {
- if (_insertionAnchor !== undefined) {
+ if (_isLastInsertion) {
advanceHydrationNode(_insertionParent!)
}
}
import {
insertionAnchor,
insertionParent,
+ isLastInsertion,
resetInsertionState,
} from './insertionState'
import { applyTransitionHooks } from './components/Transition'
): ForFragment => {
const _insertionParent = insertionParent
const _insertionAnchor = insertionAnchor
+ const _isLastInsertion = isLastInsertion
if (isHydrating) {
locateHydrationNode()
} else {
if (!isHydrating) {
if (_insertionParent) insert(frag, _insertionParent, _insertionAnchor)
} else {
- advanceHydrationNode(
- _insertionAnchor !== undefined ? _insertionParent! : parentAnchor!,
- )
+ advanceHydrationNode(_isLastInsertion ? _insertionParent! : parentAnchor!)
}
return frag
import {
insertionAnchor,
insertionParent,
+ isLastInsertion,
resetInsertionState,
} from './insertionState'
import { renderEffect } from './renderEffect'
): Block {
const _insertionParent = insertionParent
const _insertionAnchor = insertionAnchor
+ const _isLastInsertion = isLastInsertion
if (!isHydrating) resetInsertionState()
let frag: Block
if (!isHydrating) {
if (_insertionParent) insert(frag, _insertionParent, _insertionAnchor)
} else {
- // After block node hydration is completed, advance currentHydrationNode to
- // _insertionParent's next sibling if _insertionAnchor has a value
- // _insertionAnchor values:
- // 1. Node type: _insertionAnchor is a static node, no hydration needed
- // 2. null: block node is appended, potentially without next sibling
- // 3. 0: next sibling of current block node is static, no hydration needed
- if (_insertionAnchor !== undefined) {
+ if (_isLastInsertion) {
advanceHydrationNode(_insertionParent!)
}
}
import {
insertionAnchor,
insertionParent,
+ isLastInsertion,
resetInsertionState,
} from './insertionState'
import { DynamicFragment } from './fragment'
): VaporComponentInstance {
const _insertionParent = insertionParent
const _insertionAnchor = insertionAnchor
+ const _isLastInsertion = isLastInsertion
if (isHydrating) {
locateHydrationNode()
} else {
if (_insertionParent) insert(frag, _insertionParent, _insertionAnchor)
} else {
frag.hydrate()
- if (_insertionAnchor !== undefined) {
+ if (_isLastInsertion) {
advanceHydrationNode(_insertionParent!)
}
}
if (_insertionParent) insert(frag, _insertionParent, _insertionAnchor)
} else {
frag.hydrate()
- if (_insertionAnchor !== undefined) {
+ if (_isLastInsertion) {
advanceHydrationNode(_insertionParent!)
}
}
const _insertionParent = insertionParent
const _insertionAnchor = insertionAnchor
+ const _isLastInsertion = isLastInsertion
if (isHydrating) {
locateHydrationNode()
} else {
if (!isHydrating) {
if (_insertionParent) insert(el, _insertionParent, _insertionAnchor)
} else {
- if (_insertionAnchor !== undefined) {
+ if (_isLastInsertion) {
advanceHydrationNode(_insertionParent!)
}
}
import {
insertionAnchor,
insertionParent,
+ isLastInsertion,
resetInsertionState,
} from './insertionState'
import {
): Block {
const _insertionParent = insertionParent
const _insertionAnchor = insertionAnchor
+ const _isLastInsertion = isLastInsertion
if (!isHydrating) resetInsertionState()
const instance = i || (currentInstance as VaporComponentInstance)
if (_insertionParent) {
updateLastLogicalChild(_insertionParent!, fragment.anchor)
}
- if (_insertionAnchor !== undefined) {
+ if (_isLastInsertion) {
advanceHydrationNode(_insertionParent!)
}
}
export let insertionParent: InsertionParent | undefined
export let insertionAnchor: Node | 0 | undefined | null
+// indicates whether the insertion is the last one in the parent.
+// if true, means no more nodes need to be hydrated after this insertion,
+// advancing current hydration node to parent nextSibling
+export let isLastInsertion: boolean | undefined
+
/**
* This function is called before a block type that requires insertion
* (component, slot outlet, if, for) is created. The state is used for actual
export function setInsertionState(
parent: ParentNode & { $fc?: Node | null },
anchor?: Node | 0 | null | number,
+ last?: boolean,
): void {
insertionParent = parent
+ isLastInsertion = last
if (anchor !== undefined) {
if (isHydrating) {
}
export function resetInsertionState(): void {
- insertionParent = insertionAnchor = undefined
+ insertionParent = insertionAnchor = isLastInsertion = undefined
}