From 0c2f404a30b3643888f95af9cdbe53a32c1b9190 Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Thu, 31 Jul 2025 13:15:07 +0800 Subject: [PATCH 01/24] fix(vapor): avoid unnecessary block movement in renderList --- packages/runtime-vapor/src/apiCreateFor.ts | 233 +++++++++++++-------- 1 file changed, 148 insertions(+), 85 deletions(-) diff --git a/packages/runtime-vapor/src/apiCreateFor.ts b/packages/runtime-vapor/src/apiCreateFor.ts index bdd2af7b348..9d90dac7378 100644 --- a/packages/runtime-vapor/src/apiCreateFor.ts +++ b/packages/runtime-vapor/src/apiCreateFor.ts @@ -34,6 +34,8 @@ import { class ForBlock extends VaporFragment { scope: EffectScope | undefined key: any + prev: ForBlock | undefined + next: ForBlock | undefined itemRef: ShallowRef keyRef: ShallowRef | undefined @@ -90,7 +92,7 @@ export const createFor = ( let oldBlocks: ForBlock[] = [] let newBlocks: ForBlock[] let parent: ParentNode | undefined | null - // useSelector only + // createSelector only let currentKey: any // TODO handle this in hydration const parentAnchor = __DEV__ ? createComment('for') : createTextNode() @@ -233,107 +235,145 @@ export const createFor = ( ] } - const preparationBlockCount = Math.min( - newLength - endOffset, - sharedBlockCount, - ) - for (let i = startOffset; i < preparationBlockCount; i++) { + for (let i = startOffset; i < newLength - endOffset; i++) { const blockItem = getItem(source, i) const blockKey = getKey(...blockItem) queuedBlocks[queuedBlocksInsertIndex++] = [i, blockItem, blockKey] } - if (!queuedBlocksInsertIndex && !previousKeyIndexInsertIndex) { - for (let i = preparationBlockCount; i < newLength - endOffset; i++) { - const blockItem = getItem(source, i) - const blockKey = getKey(...blockItem) - mount(source, i, anchorFallback, blockItem, blockKey) - } - } else { - queuedBlocks.length = queuedBlocksInsertIndex - previousKeyIndexPairs.length = previousKeyIndexInsertIndex - - const previousKeyIndexMap = new Map(previousKeyIndexPairs) - const operations: (() => void)[] = [] - - let mountCounter = 0 - const relocateOrMountBlock = ( - blockIndex: number, - blockItem: ReturnType, - blockKey: any, - anchorOffset: number, - ) => { - const previousIndex = previousKeyIndexMap.get(blockKey) - if (previousIndex !== undefined) { - const reusedBlock = (newBlocks[blockIndex] = - oldBlocks[previousIndex]) - update(reusedBlock, ...blockItem) - previousKeyIndexMap.delete(blockKey) - if (previousIndex !== blockIndex) { - operations.push(() => - insert( - reusedBlock, - parent!, - anchorOffset === -1 - ? anchorFallback - : normalizeAnchor(newBlocks[anchorOffset].nodes), - ), - ) + queuedBlocks.length = queuedBlocksInsertIndex + previousKeyIndexPairs.length = previousKeyIndexInsertIndex + + const previousKeyIndexMap = new Map(previousKeyIndexPairs) + const actions: ( + | [ + type: 'mount', + source: ResolvedSource, + index: number, + item: ReturnType, + key: any, + ] + | [type: 'insert', index: number, block: ForBlock] + )[] = [] + + let mountCounter = 0 + const relocateOrMountBlock: ( + index: number, + item: ReturnType, + key: any, + ) => void = previousKeyIndexMap.size + ? (blockIndex, blockItem, blockKey) => { + const previousIndex = previousKeyIndexMap.get(blockKey) + if (previousIndex !== undefined) { + const reusedBlock = (newBlocks[blockIndex] = + oldBlocks[previousIndex]) + update(reusedBlock, ...blockItem) + actions.push(['insert', blockIndex, reusedBlock]) + previousKeyIndexMap.delete(blockKey) + } else { + mountCounter++ + actions.push(['mount', source, blockIndex, blockItem, blockKey]) } - } else { + } + : (blockIndex, blockItem, blockKey) => { mountCounter++ - operations.push(() => - mount( - source, - blockIndex, - anchorOffset === -1 - ? anchorFallback - : normalizeAnchor(newBlocks[anchorOffset].nodes), - blockItem, - blockKey, - ), - ) + actions.push(['mount', source, blockIndex, blockItem, blockKey]) } - } - for (let i = queuedBlocks.length - 1; i >= 0; i--) { - const [blockIndex, blockItem, blockKey] = queuedBlocks[i] - relocateOrMountBlock( - blockIndex, - blockItem, - blockKey, - blockIndex < preparationBlockCount - 1 ? blockIndex + 1 : -1, - ) - } + for (let i = queuedBlocks.length - 1; i >= 0; i--) { + const [blockIndex, blockItem, blockKey] = queuedBlocks[i] + relocateOrMountBlock(blockIndex, blockItem, blockKey) + } - for (let i = preparationBlockCount; i < newLength - endOffset; i++) { - const blockItem = getItem(source, i) - const blockKey = getKey(...blockItem) - relocateOrMountBlock(i, blockItem, blockKey, -1) - } + const useFastRemove = mountCounter === newLength - const useFastRemove = mountCounter === newLength + for (const leftoverIndex of previousKeyIndexMap.values()) { + const oldBlock = oldBlocks[leftoverIndex] + unmount( + oldBlock, + !(useFastRemove && canUseFastRemove), + !useFastRemove, + ) + moveLink(oldBlock, undefined, undefined) + oldBlocks[leftoverIndex] = undefined as any + } + if (useFastRemove) { + for (const selector of selectors) { + selector.cleanup() + } + if (canUseFastRemove) { + parent!.textContent = '' + parent!.appendChild(parentAnchor) + } + } - for (const leftoverIndex of previousKeyIndexMap.values()) { - unmount( - oldBlocks[leftoverIndex], - !(useFastRemove && canUseFastRemove), - !useFastRemove, + if (actions.length === mountCounter) { + for (const action of actions) { + const [_type, source, index, item, key] = action as [ + type: 'mount', + source: ResolvedSource, + index: number, + item: ReturnType, + key: any, + ] + mount( + source, + index, + index < newLength - 1 + ? normalizeAnchor(newBlocks[index + 1].nodes) + : anchorFallback, + item, + key, ) } - if (useFastRemove) { - for (const selector of selectors) { - selector.cleanup() + } else if (actions.length) { + let blockTail: ForBlock | undefined + for (const block of oldBlocks) { + if (block === undefined) { + continue } - if (canUseFastRemove) { - parent!.textContent = '' - parent!.appendChild(parentAnchor) + if (blockTail !== undefined) { + blockTail.next = block + block.prev = blockTail } + blockTail = block } - - // perform mount and move operations - for (const action of operations) { - action() + for (const action of actions) { + if (action[0] === 'mount') { + const [_type, source, index, item, key] = action + if (index < newLength - 1) { + const anchorBlock = newBlocks[index + 1] + const block = mount( + source, + index, + normalizeAnchor(anchorBlock.nodes), + item, + key, + ) + moveLink(block, anchorBlock.prev, anchorBlock) + } else { + const block = mount(source, index, anchorFallback, item, key) + moveLink(block, blockTail, undefined) + blockTail = block + } + } else { + const [_type, index, block] = action + if (index < newLength - 1) { + const anchorBlock = newBlocks[index + 1] + if (anchorBlock !== block.next) { + insert( + block, + parent!, + normalizeAnchor(newBlocks[index + 1].nodes), + ) + moveLink(block, anchorBlock.prev, anchorBlock) + } + } else if (block.next !== undefined) { + insert(block, parent!, anchorFallback) + moveLink(block, blockTail, undefined) + blockTail = block + } + } } } } @@ -486,6 +526,29 @@ export const createFor = ( } } +function moveLink( + block: ForBlock, + prev: ForBlock | undefined, + next: ForBlock | undefined, +) { + const oldPrev = block.prev + const oldNext = block.next + if (oldPrev !== undefined) { + oldPrev.next = oldNext + } + if (oldNext !== undefined) { + oldNext.prev = oldPrev + } + if (prev !== undefined) { + prev.next = block + } + if (next !== undefined) { + next.prev = block + } + block.prev = prev + block.next = next +} + export function createForSlots( rawSource: Source, getSlot: (item: any, key: any, index?: number) => DynamicSlot, From 6a86914d29321b3265ee4e522b90323ac5c8725f Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Thu, 31 Jul 2025 13:18:05 +0800 Subject: [PATCH 02/24] Update apiCreateFor.ts --- packages/runtime-vapor/src/apiCreateFor.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/runtime-vapor/src/apiCreateFor.ts b/packages/runtime-vapor/src/apiCreateFor.ts index 9d90dac7378..7aab32b3a79 100644 --- a/packages/runtime-vapor/src/apiCreateFor.ts +++ b/packages/runtime-vapor/src/apiCreateFor.ts @@ -327,16 +327,16 @@ export const createFor = ( ) } } else if (actions.length) { - let blockTail: ForBlock | undefined + let blocksTail: ForBlock | undefined for (const block of oldBlocks) { if (block === undefined) { continue } - if (blockTail !== undefined) { - blockTail.next = block - block.prev = blockTail + if (blocksTail !== undefined) { + blocksTail.next = block + block.prev = blocksTail } - blockTail = block + blocksTail = block } for (const action of actions) { if (action[0] === 'mount') { @@ -353,8 +353,8 @@ export const createFor = ( moveLink(block, anchorBlock.prev, anchorBlock) } else { const block = mount(source, index, anchorFallback, item, key) - moveLink(block, blockTail, undefined) - blockTail = block + moveLink(block, blocksTail, undefined) + blocksTail = block } } else { const [_type, index, block] = action @@ -370,8 +370,8 @@ export const createFor = ( } } else if (block.next !== undefined) { insert(block, parent!, anchorFallback) - moveLink(block, blockTail, undefined) - blockTail = block + moveLink(block, blocksTail, undefined) + blocksTail = block } } } From 825269fed0e63ca89e62f0e8bae8fe3e7669d929 Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Thu, 31 Jul 2025 13:57:17 +0800 Subject: [PATCH 03/24] Update apiCreateFor.ts --- packages/runtime-vapor/src/apiCreateFor.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/runtime-vapor/src/apiCreateFor.ts b/packages/runtime-vapor/src/apiCreateFor.ts index 7aab32b3a79..869d958c0bd 100644 --- a/packages/runtime-vapor/src/apiCreateFor.ts +++ b/packages/runtime-vapor/src/apiCreateFor.ts @@ -201,12 +201,6 @@ export const createFor = ( break } - if (endOffset !== 0) { - anchorFallback = normalizeAnchor( - newBlocks[newLength - endOffset].nodes, - ) - } - while (startOffset < sharedBlockCount - endOffset) { const currentItem = getItem(source, startOffset) const currentKey = getKey(...currentItem) From c9f0c659986981b7d0b20243ab58ec3f37703d21 Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Thu, 31 Jul 2025 14:00:34 +0800 Subject: [PATCH 04/24] Update apiCreateFor.ts --- packages/runtime-vapor/src/apiCreateFor.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/runtime-vapor/src/apiCreateFor.ts b/packages/runtime-vapor/src/apiCreateFor.ts index 869d958c0bd..5d1decbaffc 100644 --- a/packages/runtime-vapor/src/apiCreateFor.ts +++ b/packages/runtime-vapor/src/apiCreateFor.ts @@ -201,7 +201,11 @@ export const createFor = ( break } - while (startOffset < sharedBlockCount - endOffset) { + const e1 = sharedBlockCount - endOffset + const e2 = oldLength - endOffset + const e3 = newLength - endOffset + + while (startOffset < e1) { const currentItem = getItem(source, startOffset) const currentKey = getKey(...currentItem) const previousBlock = oldBlocks[startOffset] @@ -222,14 +226,14 @@ export const createFor = ( startOffset++ } - for (let i = startOffset; i < oldLength - endOffset; i++) { + for (let i = startOffset; i < e2; i++) { previousKeyIndexPairs[previousKeyIndexInsertIndex++] = [ oldBlocks[i].key, i, ] } - for (let i = startOffset; i < newLength - endOffset; i++) { + for (let i = startOffset; i < e3; i++) { const blockItem = getItem(source, i) const blockKey = getKey(...blockItem) queuedBlocks[queuedBlocksInsertIndex++] = [i, blockItem, blockKey] From f57c66395905e72b8503745bf5b977552c95c71e Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Thu, 31 Jul 2025 14:18:25 +0800 Subject: [PATCH 05/24] Update apiCreateFor.ts --- packages/runtime-vapor/src/apiCreateFor.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/packages/runtime-vapor/src/apiCreateFor.ts b/packages/runtime-vapor/src/apiCreateFor.ts index 5d1decbaffc..6b796fc6855 100644 --- a/packages/runtime-vapor/src/apiCreateFor.ts +++ b/packages/runtime-vapor/src/apiCreateFor.ts @@ -183,7 +183,6 @@ export const createFor = ( let anchorFallback: Node = parentAnchor let endOffset = 0 - let startOffset = 0 let queuedBlocksInsertIndex = 0 let previousKeyIndexInsertIndex = 0 @@ -205,35 +204,34 @@ export const createFor = ( const e2 = oldLength - endOffset const e3 = newLength - endOffset - while (startOffset < e1) { - const currentItem = getItem(source, startOffset) + for (let i = 0; i < e1; i++) { + const currentItem = getItem(source, i) const currentKey = getKey(...currentItem) - const previousBlock = oldBlocks[startOffset] + const previousBlock = oldBlocks[i] const previousKey = previousBlock.key if (previousKey === currentKey) { - update((newBlocks[startOffset] = previousBlock), currentItem[0]) + update((newBlocks[i] = previousBlock), currentItem[0]) } else { queuedBlocks[queuedBlocksInsertIndex++] = [ - startOffset, + i, currentItem, currentKey, ] previousKeyIndexPairs[previousKeyIndexInsertIndex++] = [ previousKey, - startOffset, + i, ] } - startOffset++ } - for (let i = startOffset; i < e2; i++) { + for (let i = e1; i < e2; i++) { previousKeyIndexPairs[previousKeyIndexInsertIndex++] = [ oldBlocks[i].key, i, ] } - for (let i = startOffset; i < e3; i++) { + for (let i = e1; i < e3; i++) { const blockItem = getItem(source, i) const blockKey = getKey(...blockItem) queuedBlocks[queuedBlocksInsertIndex++] = [i, blockItem, blockKey] From 66261189f8ff85dc0a9c75f857bba92e02957d07 Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Thu, 31 Jul 2025 14:20:04 +0800 Subject: [PATCH 06/24] Update apiCreateFor.ts --- packages/runtime-vapor/src/apiCreateFor.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/runtime-vapor/src/apiCreateFor.ts b/packages/runtime-vapor/src/apiCreateFor.ts index 6b796fc6855..89681fcedcd 100644 --- a/packages/runtime-vapor/src/apiCreateFor.ts +++ b/packages/runtime-vapor/src/apiCreateFor.ts @@ -181,7 +181,6 @@ export const createFor = ( blockKey: any, ][] = new Array(newLength) - let anchorFallback: Node = parentAnchor let endOffset = 0 let queuedBlocksInsertIndex = 0 let previousKeyIndexInsertIndex = 0 @@ -317,7 +316,7 @@ export const createFor = ( index, index < newLength - 1 ? normalizeAnchor(newBlocks[index + 1].nodes) - : anchorFallback, + : parentAnchor, item, key, ) @@ -348,7 +347,7 @@ export const createFor = ( ) moveLink(block, anchorBlock.prev, anchorBlock) } else { - const block = mount(source, index, anchorFallback, item, key) + const block = mount(source, index, parentAnchor, item, key) moveLink(block, blocksTail, undefined) blocksTail = block } @@ -365,7 +364,7 @@ export const createFor = ( moveLink(block, anchorBlock.prev, anchorBlock) } } else if (block.next !== undefined) { - insert(block, parent!, anchorFallback) + insert(block, parent!, parentAnchor) moveLink(block, blocksTail, undefined) blocksTail = block } From 3aa4f07749e607b6465433df2c0fd9fc3bef6759 Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Thu, 31 Jul 2025 14:23:42 +0800 Subject: [PATCH 07/24] Update apiCreateFor.ts --- packages/runtime-vapor/src/apiCreateFor.ts | 26 +++++++++------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/packages/runtime-vapor/src/apiCreateFor.ts b/packages/runtime-vapor/src/apiCreateFor.ts index 89681fcedcd..e569b10f3ec 100644 --- a/packages/runtime-vapor/src/apiCreateFor.ts +++ b/packages/runtime-vapor/src/apiCreateFor.ts @@ -173,7 +173,7 @@ export const createFor = ( } } - const sharedBlockCount = Math.min(oldLength, newLength) + const commonLength = Math.min(oldLength, newLength) const previousKeyIndexPairs: [any, number][] = new Array(oldLength) const queuedBlocks: [ blockIndex: number, @@ -182,10 +182,10 @@ export const createFor = ( ][] = new Array(newLength) let endOffset = 0 - let queuedBlocksInsertIndex = 0 - let previousKeyIndexInsertIndex = 0 + let queuedBlocksLength = 0 + let previousKeyIndexPairsLength = 0 - while (endOffset < sharedBlockCount) { + while (endOffset < commonLength) { const currentIndex = newLength - endOffset - 1 const currentItem = getItem(source, currentIndex) const currentKey = getKey(...currentItem) @@ -199,7 +199,7 @@ export const createFor = ( break } - const e1 = sharedBlockCount - endOffset + const e1 = commonLength - endOffset const e2 = oldLength - endOffset const e3 = newLength - endOffset @@ -211,12 +211,8 @@ export const createFor = ( if (previousKey === currentKey) { update((newBlocks[i] = previousBlock), currentItem[0]) } else { - queuedBlocks[queuedBlocksInsertIndex++] = [ - i, - currentItem, - currentKey, - ] - previousKeyIndexPairs[previousKeyIndexInsertIndex++] = [ + queuedBlocks[queuedBlocksLength++] = [i, currentItem, currentKey] + previousKeyIndexPairs[previousKeyIndexPairsLength++] = [ previousKey, i, ] @@ -224,7 +220,7 @@ export const createFor = ( } for (let i = e1; i < e2; i++) { - previousKeyIndexPairs[previousKeyIndexInsertIndex++] = [ + previousKeyIndexPairs[previousKeyIndexPairsLength++] = [ oldBlocks[i].key, i, ] @@ -233,11 +229,11 @@ export const createFor = ( for (let i = e1; i < e3; i++) { const blockItem = getItem(source, i) const blockKey = getKey(...blockItem) - queuedBlocks[queuedBlocksInsertIndex++] = [i, blockItem, blockKey] + queuedBlocks[queuedBlocksLength++] = [i, blockItem, blockKey] } - queuedBlocks.length = queuedBlocksInsertIndex - previousKeyIndexPairs.length = previousKeyIndexInsertIndex + queuedBlocks.length = queuedBlocksLength + previousKeyIndexPairs.length = previousKeyIndexPairsLength const previousKeyIndexMap = new Map(previousKeyIndexPairs) const actions: ( From 77465d8cad46bf407bab67efa6466e2a9ed1d549 Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Thu, 31 Jul 2025 14:29:08 +0800 Subject: [PATCH 08/24] Update apiCreateFor.ts --- packages/runtime-vapor/src/apiCreateFor.ts | 69 ++++++++-------------- 1 file changed, 25 insertions(+), 44 deletions(-) diff --git a/packages/runtime-vapor/src/apiCreateFor.ts b/packages/runtime-vapor/src/apiCreateFor.ts index e569b10f3ec..16367815be1 100644 --- a/packages/runtime-vapor/src/apiCreateFor.ts +++ b/packages/runtime-vapor/src/apiCreateFor.ts @@ -174,16 +174,16 @@ export const createFor = ( } const commonLength = Math.min(oldLength, newLength) - const previousKeyIndexPairs: [any, number][] = new Array(oldLength) + const oldKeyIndexPairs: [any, number][] = new Array(oldLength) const queuedBlocks: [ - blockIndex: number, - blockItem: ReturnType, - blockKey: any, + index: number, + item: ReturnType, + key: any, ][] = new Array(newLength) let endOffset = 0 let queuedBlocksLength = 0 - let previousKeyIndexPairsLength = 0 + let oldKeyIndexPairsLength = 0 while (endOffset < commonLength) { const currentIndex = newLength - endOffset - 1 @@ -206,24 +206,18 @@ export const createFor = ( for (let i = 0; i < e1; i++) { const currentItem = getItem(source, i) const currentKey = getKey(...currentItem) - const previousBlock = oldBlocks[i] - const previousKey = previousBlock.key - if (previousKey === currentKey) { - update((newBlocks[i] = previousBlock), currentItem[0]) + const oldBlock = oldBlocks[i] + const oldKey = oldBlock.key + if (oldKey === currentKey) { + update((newBlocks[i] = oldBlock), currentItem[0]) } else { queuedBlocks[queuedBlocksLength++] = [i, currentItem, currentKey] - previousKeyIndexPairs[previousKeyIndexPairsLength++] = [ - previousKey, - i, - ] + oldKeyIndexPairs[oldKeyIndexPairsLength++] = [oldKey, i] } } for (let i = e1; i < e2; i++) { - previousKeyIndexPairs[previousKeyIndexPairsLength++] = [ - oldBlocks[i].key, - i, - ] + oldKeyIndexPairs[oldKeyIndexPairsLength++] = [oldBlocks[i].key, i] } for (let i = e1; i < e3; i++) { @@ -233,9 +227,9 @@ export const createFor = ( } queuedBlocks.length = queuedBlocksLength - previousKeyIndexPairs.length = previousKeyIndexPairsLength + oldKeyIndexPairs.length = oldKeyIndexPairsLength - const previousKeyIndexMap = new Map(previousKeyIndexPairs) + const oldKeyIndexMap = new Map(oldKeyIndexPairs) const actions: ( | [ type: 'mount', @@ -248,37 +242,24 @@ export const createFor = ( )[] = [] let mountCounter = 0 - const relocateOrMountBlock: ( - index: number, - item: ReturnType, - key: any, - ) => void = previousKeyIndexMap.size - ? (blockIndex, blockItem, blockKey) => { - const previousIndex = previousKeyIndexMap.get(blockKey) - if (previousIndex !== undefined) { - const reusedBlock = (newBlocks[blockIndex] = - oldBlocks[previousIndex]) - update(reusedBlock, ...blockItem) - actions.push(['insert', blockIndex, reusedBlock]) - previousKeyIndexMap.delete(blockKey) - } else { - mountCounter++ - actions.push(['mount', source, blockIndex, blockItem, blockKey]) - } - } - : (blockIndex, blockItem, blockKey) => { - mountCounter++ - actions.push(['mount', source, blockIndex, blockItem, blockKey]) - } for (let i = queuedBlocks.length - 1; i >= 0; i--) { - const [blockIndex, blockItem, blockKey] = queuedBlocks[i] - relocateOrMountBlock(blockIndex, blockItem, blockKey) + const [index, item, key] = queuedBlocks[i] + const oldIndex = oldKeyIndexMap.get(key) + if (oldIndex !== undefined) { + const reusedBlock = (newBlocks[index] = oldBlocks[oldIndex]) + update(reusedBlock, ...item) + actions.push(['insert', index, reusedBlock]) + oldKeyIndexMap.delete(key) + } else { + mountCounter++ + actions.push(['mount', source, index, item, key]) + } } const useFastRemove = mountCounter === newLength - for (const leftoverIndex of previousKeyIndexMap.values()) { + for (const leftoverIndex of oldKeyIndexMap.values()) { const oldBlock = oldBlocks[leftoverIndex] unmount( oldBlock, From baccbf4169cf4fe854f50f3baee8d06bfb513662 Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Thu, 31 Jul 2025 15:37:45 +0800 Subject: [PATCH 09/24] Update apiCreateFor.ts --- packages/runtime-vapor/src/apiCreateFor.ts | 36 ++++++++++------------ 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/packages/runtime-vapor/src/apiCreateFor.ts b/packages/runtime-vapor/src/apiCreateFor.ts index 16367815be1..44641f09564 100644 --- a/packages/runtime-vapor/src/apiCreateFor.ts +++ b/packages/runtime-vapor/src/apiCreateFor.ts @@ -186,17 +186,14 @@ export const createFor = ( let oldKeyIndexPairsLength = 0 while (endOffset < commonLength) { - const currentIndex = newLength - endOffset - 1 - const currentItem = getItem(source, currentIndex) - const currentKey = getKey(...currentItem) + const index = newLength - endOffset - 1 + const item = getItem(source, index) + const key = getKey(...item) const existingBlock = oldBlocks[oldLength - endOffset - 1] - if (existingBlock.key === currentKey) { - update(existingBlock, ...currentItem) - newBlocks[currentIndex] = existingBlock - endOffset++ - continue - } - break + if (existingBlock.key !== key) break + update(existingBlock, ...item) + newBlocks[index] = existingBlock + endOffset++ } const e1 = commonLength - endOffset @@ -230,7 +227,7 @@ export const createFor = ( oldKeyIndexPairs.length = oldKeyIndexPairsLength const oldKeyIndexMap = new Map(oldKeyIndexPairs) - const actions: ( + const opers: ( | [ type: 'mount', source: ResolvedSource, @@ -239,9 +236,10 @@ export const createFor = ( key: any, ] | [type: 'insert', index: number, block: ForBlock] - )[] = [] + )[] = new Array(queuedBlocks.length) let mountCounter = 0 + let opersLength = 0 for (let i = queuedBlocks.length - 1; i >= 0; i--) { const [index, item, key] = queuedBlocks[i] @@ -249,11 +247,11 @@ export const createFor = ( if (oldIndex !== undefined) { const reusedBlock = (newBlocks[index] = oldBlocks[oldIndex]) update(reusedBlock, ...item) - actions.push(['insert', index, reusedBlock]) + opers[opersLength++] = ['insert', index, reusedBlock] oldKeyIndexMap.delete(key) } else { mountCounter++ - actions.push(['mount', source, index, item, key]) + opers[opersLength++] = ['mount', source, index, item, key] } } @@ -279,9 +277,9 @@ export const createFor = ( } } - if (actions.length === mountCounter) { - for (const action of actions) { - const [_type, source, index, item, key] = action as [ + if (opers.length === mountCounter) { + for (const oper of opers) { + const [_type, source, index, item, key] = oper as [ type: 'mount', source: ResolvedSource, index: number, @@ -298,7 +296,7 @@ export const createFor = ( key, ) } - } else if (actions.length) { + } else if (opers.length) { let blocksTail: ForBlock | undefined for (const block of oldBlocks) { if (block === undefined) { @@ -310,7 +308,7 @@ export const createFor = ( } blocksTail = block } - for (const action of actions) { + for (const action of opers) { if (action[0] === 'mount') { const [_type, source, index, item, key] = action if (index < newLength - 1) { From 013ae161dc6f4404a54b4e99255b24595d72fac6 Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Thu, 31 Jul 2025 15:41:24 +0800 Subject: [PATCH 10/24] Update apiCreateFor.ts --- packages/runtime-vapor/src/apiCreateFor.ts | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/packages/runtime-vapor/src/apiCreateFor.ts b/packages/runtime-vapor/src/apiCreateFor.ts index 44641f09564..6de6d940a5e 100644 --- a/packages/runtime-vapor/src/apiCreateFor.ts +++ b/packages/runtime-vapor/src/apiCreateFor.ts @@ -297,15 +297,12 @@ export const createFor = ( ) } } else if (opers.length) { - let blocksTail: ForBlock | undefined - for (const block of oldBlocks) { - if (block === undefined) { - continue - } - if (blocksTail !== undefined) { - blocksTail.next = block - block.prev = blocksTail - } + oldBlocks = oldBlocks.filter(block => block !== undefined) + let blocksTail = oldBlocks[0] + for (let i = 1; i < oldBlocks.length; i++) { + const block = oldBlocks[i] + blocksTail.next = block + block.prev = blocksTail blocksTail = block } for (const action of opers) { From 65a5b49c58d80e1ef744fc4cea77bb92a4740c53 Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Thu, 31 Jul 2025 15:42:37 +0800 Subject: [PATCH 11/24] Update apiCreateFor.ts --- packages/runtime-vapor/src/apiCreateFor.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/runtime-vapor/src/apiCreateFor.ts b/packages/runtime-vapor/src/apiCreateFor.ts index 6de6d940a5e..78350a1a751 100644 --- a/packages/runtime-vapor/src/apiCreateFor.ts +++ b/packages/runtime-vapor/src/apiCreateFor.ts @@ -300,10 +300,8 @@ export const createFor = ( oldBlocks = oldBlocks.filter(block => block !== undefined) let blocksTail = oldBlocks[0] for (let i = 1; i < oldBlocks.length; i++) { - const block = oldBlocks[i] - blocksTail.next = block - block.prev = blocksTail - blocksTail = block + oldBlocks[i].prev = blocksTail + blocksTail = blocksTail.next = oldBlocks[i] } for (const action of opers) { if (action[0] === 'mount') { From c46ba39f686db7bb7c00ecad28da0f4508461d8b Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Thu, 31 Jul 2025 15:45:52 +0800 Subject: [PATCH 12/24] Update apiCreateFor.ts --- packages/runtime-vapor/src/apiCreateFor.ts | 27 ++++++++-------------- 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/packages/runtime-vapor/src/apiCreateFor.ts b/packages/runtime-vapor/src/apiCreateFor.ts index 78350a1a751..088472dfda7 100644 --- a/packages/runtime-vapor/src/apiCreateFor.ts +++ b/packages/runtime-vapor/src/apiCreateFor.ts @@ -493,25 +493,16 @@ export const createFor = ( function moveLink( block: ForBlock, - prev: ForBlock | undefined, - next: ForBlock | undefined, + newPrev: ForBlock | undefined, + newNext: ForBlock | undefined, ) { - const oldPrev = block.prev - const oldNext = block.next - if (oldPrev !== undefined) { - oldPrev.next = oldNext - } - if (oldNext !== undefined) { - oldNext.prev = oldPrev - } - if (prev !== undefined) { - prev.next = block - } - if (next !== undefined) { - next.prev = block - } - block.prev = prev - block.next = next + const { prev: oldPrev, next: oldNext } = block + if (oldPrev !== undefined) oldPrev.next = oldNext + if (oldNext !== undefined) oldNext.prev = oldPrev + if (newPrev !== undefined) newPrev.next = block + if (newNext !== undefined) newNext.prev = block + block.prev = newPrev + block.next = newNext } export function createForSlots( From 64de0ff24e1642cf5f6e614b15160342523d0edc Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Thu, 31 Jul 2025 15:54:39 +0800 Subject: [PATCH 13/24] Update apiCreateFor.ts --- packages/runtime-vapor/src/apiCreateFor.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/runtime-vapor/src/apiCreateFor.ts b/packages/runtime-vapor/src/apiCreateFor.ts index 088472dfda7..6c35c26c9a1 100644 --- a/packages/runtime-vapor/src/apiCreateFor.ts +++ b/packages/runtime-vapor/src/apiCreateFor.ts @@ -258,13 +258,11 @@ export const createFor = ( const useFastRemove = mountCounter === newLength for (const leftoverIndex of oldKeyIndexMap.values()) { - const oldBlock = oldBlocks[leftoverIndex] unmount( - oldBlock, + oldBlocks[leftoverIndex], !(useFastRemove && canUseFastRemove), !useFastRemove, ) - moveLink(oldBlock, undefined, undefined) oldBlocks[leftoverIndex] = undefined as any } if (useFastRemove) { From 2dad05d46db34e1f5536a0165569f6a9785dda69 Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Thu, 31 Jul 2025 15:56:55 +0800 Subject: [PATCH 14/24] Update apiCreateFor.ts --- packages/runtime-vapor/src/apiCreateFor.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/runtime-vapor/src/apiCreateFor.ts b/packages/runtime-vapor/src/apiCreateFor.ts index 6c35c26c9a1..27e21d70d1a 100644 --- a/packages/runtime-vapor/src/apiCreateFor.ts +++ b/packages/runtime-vapor/src/apiCreateFor.ts @@ -276,14 +276,13 @@ export const createFor = ( } if (opers.length === mountCounter) { - for (const oper of opers) { - const [_type, source, index, item, key] = oper as [ - type: 'mount', - source: ResolvedSource, - index: number, - item: ReturnType, - key: any, - ] + for (const [_type, source, index, item, key] of opers as [ + type: 'mount', + source: ResolvedSource, + index: number, + item: ReturnType, + key: any, + ]) { mount( source, index, From 9be799f21630c65e97225d589f84c760e12cf58e Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Thu, 31 Jul 2025 15:59:53 +0800 Subject: [PATCH 15/24] Update apiCreateFor.ts --- packages/runtime-vapor/src/apiCreateFor.ts | 42 +++++++++++----------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/packages/runtime-vapor/src/apiCreateFor.ts b/packages/runtime-vapor/src/apiCreateFor.ts index 27e21d70d1a..83fa07bf848 100644 --- a/packages/runtime-vapor/src/apiCreateFor.ts +++ b/packages/runtime-vapor/src/apiCreateFor.ts @@ -226,17 +226,21 @@ export const createFor = ( queuedBlocks.length = queuedBlocksLength oldKeyIndexPairs.length = oldKeyIndexPairsLength + interface MountOper { + type: 'mount' + source: ResolvedSource + index: number + item: ReturnType + key: any + } + interface InsertOper { + type: 'insert' + index: number + block: ForBlock + } + const oldKeyIndexMap = new Map(oldKeyIndexPairs) - const opers: ( - | [ - type: 'mount', - source: ResolvedSource, - index: number, - item: ReturnType, - key: any, - ] - | [type: 'insert', index: number, block: ForBlock] - )[] = new Array(queuedBlocks.length) + const opers: (MountOper | InsertOper)[] = new Array(queuedBlocks.length) let mountCounter = 0 let opersLength = 0 @@ -247,11 +251,11 @@ export const createFor = ( if (oldIndex !== undefined) { const reusedBlock = (newBlocks[index] = oldBlocks[oldIndex]) update(reusedBlock, ...item) - opers[opersLength++] = ['insert', index, reusedBlock] + opers[opersLength++] = { type: 'insert', index, block: reusedBlock } oldKeyIndexMap.delete(key) } else { mountCounter++ - opers[opersLength++] = ['mount', source, index, item, key] + opers[opersLength++] = { type: 'mount', source, index, item, key } } } @@ -276,13 +280,7 @@ export const createFor = ( } if (opers.length === mountCounter) { - for (const [_type, source, index, item, key] of opers as [ - type: 'mount', - source: ResolvedSource, - index: number, - item: ReturnType, - key: any, - ]) { + for (const { source, index, item, key } of opers as MountOper[]) { mount( source, index, @@ -301,8 +299,8 @@ export const createFor = ( blocksTail = blocksTail.next = oldBlocks[i] } for (const action of opers) { - if (action[0] === 'mount') { - const [_type, source, index, item, key] = action + if (action.type === 'mount') { + const { source, index, item, key } = action if (index < newLength - 1) { const anchorBlock = newBlocks[index + 1] const block = mount( @@ -319,7 +317,7 @@ export const createFor = ( blocksTail = block } } else { - const [_type, index, block] = action + const { index, block } = action if (index < newLength - 1) { const anchorBlock = newBlocks[index + 1] if (anchorBlock !== block.next) { From 7ac570b1ca6150c30ba2b1c2722aeb4bcf3afbd4 Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Thu, 31 Jul 2025 16:01:58 +0800 Subject: [PATCH 16/24] Update apiCreateFor.ts --- packages/runtime-vapor/src/apiCreateFor.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime-vapor/src/apiCreateFor.ts b/packages/runtime-vapor/src/apiCreateFor.ts index 83fa07bf848..717a2d2b61f 100644 --- a/packages/runtime-vapor/src/apiCreateFor.ts +++ b/packages/runtime-vapor/src/apiCreateFor.ts @@ -249,10 +249,10 @@ export const createFor = ( const [index, item, key] = queuedBlocks[i] const oldIndex = oldKeyIndexMap.get(key) if (oldIndex !== undefined) { + oldKeyIndexMap.delete(key) const reusedBlock = (newBlocks[index] = oldBlocks[oldIndex]) update(reusedBlock, ...item) opers[opersLength++] = { type: 'insert', index, block: reusedBlock } - oldKeyIndexMap.delete(key) } else { mountCounter++ opers[opersLength++] = { type: 'mount', source, index, item, key } From 98a51244d5ac23784a580ff12a7cd3d902926f3d Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Thu, 31 Jul 2025 16:09:04 +0800 Subject: [PATCH 17/24] Revert "Update apiCreateFor.ts" This reverts commit 64de0ff24e1642cf5f6e614b15160342523d0edc. --- packages/runtime-vapor/src/apiCreateFor.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/runtime-vapor/src/apiCreateFor.ts b/packages/runtime-vapor/src/apiCreateFor.ts index 717a2d2b61f..a5d6bef3fc4 100644 --- a/packages/runtime-vapor/src/apiCreateFor.ts +++ b/packages/runtime-vapor/src/apiCreateFor.ts @@ -262,11 +262,13 @@ export const createFor = ( const useFastRemove = mountCounter === newLength for (const leftoverIndex of oldKeyIndexMap.values()) { + const oldBlock = oldBlocks[leftoverIndex] unmount( - oldBlocks[leftoverIndex], + oldBlock, !(useFastRemove && canUseFastRemove), !useFastRemove, ) + moveLink(oldBlock, undefined, undefined) oldBlocks[leftoverIndex] = undefined as any } if (useFastRemove) { From bbe27e810ffc411c7007f1b228e0c926dbc0a935 Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Thu, 31 Jul 2025 16:19:27 +0800 Subject: [PATCH 18/24] Update apiCreateFor.ts --- packages/runtime-vapor/src/apiCreateFor.ts | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/packages/runtime-vapor/src/apiCreateFor.ts b/packages/runtime-vapor/src/apiCreateFor.ts index a5d6bef3fc4..9cec1b99b93 100644 --- a/packages/runtime-vapor/src/apiCreateFor.ts +++ b/packages/runtime-vapor/src/apiCreateFor.ts @@ -89,6 +89,7 @@ export const createFor = ( } let isMounted = false + let hasLinkedBlocks = false let oldBlocks: ForBlock[] = [] let newBlocks: ForBlock[] let parent: ParentNode | undefined | null @@ -262,14 +263,12 @@ export const createFor = ( const useFastRemove = mountCounter === newLength for (const leftoverIndex of oldKeyIndexMap.values()) { - const oldBlock = oldBlocks[leftoverIndex] unmount( - oldBlock, + oldBlocks[leftoverIndex], !(useFastRemove && canUseFastRemove), !useFastRemove, ) - moveLink(oldBlock, undefined, undefined) - oldBlocks[leftoverIndex] = undefined as any + if (hasLinkedBlocks) moveLink(oldBlocks[leftoverIndex]) } if (useFastRemove) { for (const selector of selectors) { @@ -294,7 +293,8 @@ export const createFor = ( ) } } else if (opers.length) { - oldBlocks = oldBlocks.filter(block => block !== undefined) + hasLinkedBlocks = true + oldBlocks = oldBlocks.filter(block => !oldKeyIndexMap.has(block.key)) let blocksTail = oldBlocks[0] for (let i = 1; i < oldBlocks.length; i++) { oldBlocks[i].prev = blocksTail @@ -315,7 +315,7 @@ export const createFor = ( moveLink(block, anchorBlock.prev, anchorBlock) } else { const block = mount(source, index, parentAnchor, item, key) - moveLink(block, blocksTail, undefined) + moveLink(block, blocksTail) blocksTail = block } } else { @@ -332,7 +332,7 @@ export const createFor = ( } } else if (block.next !== undefined) { insert(block, parent!, parentAnchor) - moveLink(block, blocksTail, undefined) + moveLink(block, blocksTail) blocksTail = block } } @@ -488,11 +488,7 @@ export const createFor = ( } } -function moveLink( - block: ForBlock, - newPrev: ForBlock | undefined, - newNext: ForBlock | undefined, -) { +function moveLink(block: ForBlock, newPrev?: ForBlock, newNext?: ForBlock) { const { prev: oldPrev, next: oldNext } = block if (oldPrev !== undefined) oldPrev.next = oldNext if (oldNext !== undefined) oldNext.prev = oldPrev From 6f93ca9e01ae22c3c18102f3b18a12f535693511 Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Fri, 1 Aug 2025 13:06:26 +0800 Subject: [PATCH 19/24] add prevAnchor --- packages/runtime-vapor/src/apiCreateFor.ts | 31 +++++++++++++++------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/packages/runtime-vapor/src/apiCreateFor.ts b/packages/runtime-vapor/src/apiCreateFor.ts index 9cec1b99b93..2427a18c585 100644 --- a/packages/runtime-vapor/src/apiCreateFor.ts +++ b/packages/runtime-vapor/src/apiCreateFor.ts @@ -36,6 +36,7 @@ class ForBlock extends VaporFragment { key: any prev: ForBlock | undefined next: ForBlock | undefined + prevAnchor: ForBlock | undefined itemRef: ShallowRef keyRef: ShallowRef | undefined @@ -89,7 +90,6 @@ export const createFor = ( } let isMounted = false - let hasLinkedBlocks = false let oldBlocks: ForBlock[] = [] let newBlocks: ForBlock[] let parent: ParentNode | undefined | null @@ -268,7 +268,6 @@ export const createFor = ( !(useFastRemove && canUseFastRemove), !useFastRemove, ) - if (hasLinkedBlocks) moveLink(oldBlocks[leftoverIndex]) } if (useFastRemove) { for (const selector of selectors) { @@ -293,18 +292,26 @@ export const createFor = ( ) } } else if (opers.length) { - hasLinkedBlocks = true - oldBlocks = oldBlocks.filter(block => !oldKeyIndexMap.has(block.key)) - let blocksTail = oldBlocks[0] - for (let i = 1; i < oldBlocks.length; i++) { - oldBlocks[i].prev = blocksTail - blocksTail = blocksTail.next = oldBlocks[i] + let anchor = oldBlocks[0] + let blocksTail: ForBlock | undefined + for (let i = 0; i < oldLength; i++) { + const block = oldBlocks[i] + if (oldKeyIndexMap.has(block.key)) { + continue + } + block.prevAnchor = anchor + anchor = oldBlocks[i + 1] + if (blocksTail !== undefined) { + blocksTail.next = block + block.prev = blocksTail + } + blocksTail = block } for (const action of opers) { if (action.type === 'mount') { const { source, index, item, key } = action if (index < newLength - 1) { - const anchorBlock = newBlocks[index + 1] + const anchorBlock = newBlocks[index + 1].prevAnchor! const block = mount( source, index, @@ -326,7 +333,7 @@ export const createFor = ( insert( block, parent!, - normalizeAnchor(newBlocks[index + 1].nodes), + normalizeAnchor(newBlocks[index + 1].prevAnchor!.nodes), ) moveLink(block, anchorBlock.prev, anchorBlock) } @@ -337,6 +344,9 @@ export const createFor = ( } } } + for (const block of newBlocks) { + block.prevAnchor = block.next = block.prev = undefined + } } } } @@ -496,6 +506,7 @@ function moveLink(block: ForBlock, newPrev?: ForBlock, newNext?: ForBlock) { if (newNext !== undefined) newNext.prev = block block.prev = newPrev block.next = newNext + block.prevAnchor = block } export function createForSlots( From 446a6502941c7cddca88b296c89ef70950b8257e Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Fri, 1 Aug 2025 13:39:31 +0800 Subject: [PATCH 20/24] add fallbackAnchor --- packages/runtime-vapor/src/apiCreateFor.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/runtime-vapor/src/apiCreateFor.ts b/packages/runtime-vapor/src/apiCreateFor.ts index 2427a18c585..46b1a57e6de 100644 --- a/packages/runtime-vapor/src/apiCreateFor.ts +++ b/packages/runtime-vapor/src/apiCreateFor.ts @@ -307,6 +307,13 @@ export const createFor = ( } blocksTail = block } + let fallbackAnchor: Node = parentAnchor + if (anchor) { + const node = normalizeAnchor(anchor.nodes) + if (node.parentNode) { + fallbackAnchor = node + } + } for (const action of opers) { if (action.type === 'mount') { const { source, index, item, key } = action @@ -321,7 +328,7 @@ export const createFor = ( ) moveLink(block, anchorBlock.prev, anchorBlock) } else { - const block = mount(source, index, parentAnchor, item, key) + const block = mount(source, index, fallbackAnchor, item, key) moveLink(block, blocksTail) blocksTail = block } @@ -338,7 +345,7 @@ export const createFor = ( moveLink(block, anchorBlock.prev, anchorBlock) } } else if (block.next !== undefined) { - insert(block, parent!, parentAnchor) + insert(block, parent!, fallbackAnchor) moveLink(block, blocksTail) blocksTail = block } From 2e784ffedc61935404ff83bbdbac5c4f605d7323 Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Fri, 1 Aug 2025 14:18:16 +0800 Subject: [PATCH 21/24] Update vitest.config.ts --- packages/runtime-vapor/src/apiCreateFor.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/runtime-vapor/src/apiCreateFor.ts b/packages/runtime-vapor/src/apiCreateFor.ts index 46b1a57e6de..84e97375dc5 100644 --- a/packages/runtime-vapor/src/apiCreateFor.ts +++ b/packages/runtime-vapor/src/apiCreateFor.ts @@ -307,13 +307,6 @@ export const createFor = ( } blocksTail = block } - let fallbackAnchor: Node = parentAnchor - if (anchor) { - const node = normalizeAnchor(anchor.nodes) - if (node.parentNode) { - fallbackAnchor = node - } - } for (const action of opers) { if (action.type === 'mount') { const { source, index, item, key } = action @@ -328,7 +321,7 @@ export const createFor = ( ) moveLink(block, anchorBlock.prev, anchorBlock) } else { - const block = mount(source, index, fallbackAnchor, item, key) + const block = mount(source, index, parentAnchor, item, key) moveLink(block, blocksTail) blocksTail = block } @@ -345,6 +338,13 @@ export const createFor = ( moveLink(block, anchorBlock.prev, anchorBlock) } } else if (block.next !== undefined) { + let fallbackAnchor: Node = parentAnchor + if (anchor) { + const node = normalizeAnchor(anchor.nodes) + if (node.parentNode) { + fallbackAnchor = node + } + } insert(block, parent!, fallbackAnchor) moveLink(block, blocksTail) blocksTail = block From 3313006644a7e97f180b55ee3adfc1adc06bd66e Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Fri, 1 Aug 2025 14:52:34 +0800 Subject: [PATCH 22/24] handle non-transition --- packages/runtime-vapor/src/apiCreateFor.ts | 43 +++++++++------------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/packages/runtime-vapor/src/apiCreateFor.ts b/packages/runtime-vapor/src/apiCreateFor.ts index 84e97375dc5..231f94cb679 100644 --- a/packages/runtime-vapor/src/apiCreateFor.ts +++ b/packages/runtime-vapor/src/apiCreateFor.ts @@ -311,15 +311,12 @@ export const createFor = ( if (action.type === 'mount') { const { source, index, item, key } = action if (index < newLength - 1) { - const anchorBlock = newBlocks[index + 1].prevAnchor! - const block = mount( - source, - index, - normalizeAnchor(anchorBlock.nodes), - item, - key, - ) - moveLink(block, anchorBlock.prev, anchorBlock) + const nextBlock = newBlocks[index + 1] + let anchorNode = normalizeAnchor(nextBlock.prevAnchor!.nodes) + if (!anchorNode.parentNode) + anchorNode = normalizeAnchor(nextBlock.nodes) + const block = mount(source, index, anchorNode, item, key) + moveLink(block, nextBlock.prev, nextBlock) } else { const block = mount(source, index, parentAnchor, item, key) moveLink(block, blocksTail) @@ -328,24 +325,20 @@ export const createFor = ( } else { const { index, block } = action if (index < newLength - 1) { - const anchorBlock = newBlocks[index + 1] - if (anchorBlock !== block.next) { - insert( - block, - parent!, - normalizeAnchor(newBlocks[index + 1].prevAnchor!.nodes), - ) - moveLink(block, anchorBlock.prev, anchorBlock) + const nextBlock = newBlocks[index + 1] + if (block.next !== nextBlock) { + let anchorNode = normalizeAnchor(nextBlock.prevAnchor!.nodes) + if (!anchorNode.parentNode) + anchorNode = normalizeAnchor(nextBlock.nodes) + insert(block, parent!, anchorNode) + moveLink(block, nextBlock.prev, nextBlock) } } else if (block.next !== undefined) { - let fallbackAnchor: Node = parentAnchor - if (anchor) { - const node = normalizeAnchor(anchor.nodes) - if (node.parentNode) { - fallbackAnchor = node - } - } - insert(block, parent!, fallbackAnchor) + let anchorNode: Node = anchor + ? normalizeAnchor(anchor.nodes) + : parentAnchor + if (!anchorNode.parentNode) anchorNode = parentAnchor + insert(block, parent!, anchorNode) moveLink(block, blocksTail) blocksTail = block } From 5cd0610550650dbbb29d839afca0c1cd01050cc4 Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Fri, 1 Aug 2025 15:06:01 +0800 Subject: [PATCH 23/24] Update apiCreateFor.ts --- packages/runtime-vapor/src/apiCreateFor.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/runtime-vapor/src/apiCreateFor.ts b/packages/runtime-vapor/src/apiCreateFor.ts index 231f94cb679..49628651346 100644 --- a/packages/runtime-vapor/src/apiCreateFor.ts +++ b/packages/runtime-vapor/src/apiCreateFor.ts @@ -500,10 +500,10 @@ export const createFor = ( function moveLink(block: ForBlock, newPrev?: ForBlock, newNext?: ForBlock) { const { prev: oldPrev, next: oldNext } = block - if (oldPrev !== undefined) oldPrev.next = oldNext - if (oldNext !== undefined) oldNext.prev = oldPrev - if (newPrev !== undefined) newPrev.next = block - if (newNext !== undefined) newNext.prev = block + if (oldPrev) oldPrev.next = oldNext + if (oldNext) oldNext.prev = oldPrev + if (newPrev) newPrev.next = block + if (newNext) newNext.prev = block block.prev = newPrev block.next = newNext block.prevAnchor = block From 19e7a44e9605c601b364d3fd45b8d5ad5b653ba7 Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Fri, 1 Aug 2025 15:28:14 +0800 Subject: [PATCH 24/24] inherit prevAnchor on move --- packages/runtime-vapor/src/apiCreateFor.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/runtime-vapor/src/apiCreateFor.ts b/packages/runtime-vapor/src/apiCreateFor.ts index 49628651346..f91dcb38525 100644 --- a/packages/runtime-vapor/src/apiCreateFor.ts +++ b/packages/runtime-vapor/src/apiCreateFor.ts @@ -501,7 +501,12 @@ export const createFor = ( function moveLink(block: ForBlock, newPrev?: ForBlock, newNext?: ForBlock) { const { prev: oldPrev, next: oldNext } = block if (oldPrev) oldPrev.next = oldNext - if (oldNext) oldNext.prev = oldPrev + if (oldNext) { + oldNext.prev = oldPrev + if (block.prevAnchor !== block) { + oldNext.prevAnchor = block.prevAnchor + } + } if (newPrev) newPrev.next = block if (newNext) newNext.prev = block block.prev = newPrev