From f9ff6eb1efe6e9c28d82e3558de0cad07401a170 Mon Sep 17 00:00:00 2001 From: linzhe141 <1572213544@qq.com> Date: Thu, 3 Jul 2025 17:57:28 +0800 Subject: [PATCH 1/7] wip: . --- packages/runtime-core/src/renderer.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index a57be791a44..ce97987fe07 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -1979,8 +1979,15 @@ function baseCreateRenderer( for (i = toBePatched - 1; i >= 0; i--) { const nextIndex = s2 + i const nextChild = c2[nextIndex] as VNode - const anchor = - nextIndex + 1 < l2 ? (c2[nextIndex + 1] as VNode).el : parentAnchor + let anchor = parentAnchor + if (nextIndex + 1 < l2) { + const anchorVnode = c2[nextIndex + 1] as VNode + if (anchorVnode.component && !anchorVnode.component.asyncResolved) { + anchor = anchorVnode.component.subTree.el + } else { + anchor = anchorVnode.el + } + } if (newIndexToOldIndexMap[i] === 0) { // mount new patch( From 5296f376874cecfdf944d4c25599845c6c3548e7 Mon Sep 17 00:00:00 2001 From: linzhe Date: Thu, 3 Jul 2025 21:41:08 +0800 Subject: [PATCH 2/7] wip: . --- packages/runtime-core/src/renderer.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index ce97987fe07..15db1b5856d 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -1982,7 +1982,12 @@ function baseCreateRenderer( let anchor = parentAnchor if (nextIndex + 1 < l2) { const anchorVnode = c2[nextIndex + 1] as VNode - if (anchorVnode.component && !anchorVnode.component.asyncResolved) { + if ( + __FEATURE_SUSPENSE__ && + anchorVnode.component && + anchorVnode.component.asyncDep && + !anchorVnode.component.asyncResolved + ) { anchor = anchorVnode.component.subTree.el } else { anchor = anchorVnode.el From 9308402dc4ed5f5231a2c820452934ca34fb796f Mon Sep 17 00:00:00 2001 From: linzhe Date: Thu, 3 Jul 2025 22:03:21 +0800 Subject: [PATCH 3/7] chore: udpate --- packages/runtime-core/src/renderer.ts | 33 +++++++++++++++------------ 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index 15db1b5856d..fca76026a30 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -1979,20 +1979,10 @@ function baseCreateRenderer( for (i = toBePatched - 1; i >= 0; i--) { const nextIndex = s2 + i const nextChild = c2[nextIndex] as VNode - let anchor = parentAnchor - if (nextIndex + 1 < l2) { - const anchorVnode = c2[nextIndex + 1] as VNode - if ( - __FEATURE_SUSPENSE__ && - anchorVnode.component && - anchorVnode.component.asyncDep && - !anchorVnode.component.asyncResolved - ) { - anchor = anchorVnode.component.subTree.el - } else { - anchor = anchorVnode.el - } - } + const anchor = + nextIndex + 1 < l2 + ? resolveInsertionAnchor(c2[nextIndex + 1] as VNode) + : parentAnchor if (newIndexToOldIndexMap[i] === 0) { // mount new patch( @@ -2578,6 +2568,21 @@ function getSequence(arr: number[]): number[] { return result } +function resolveInsertionAnchor(anchorVnode: VNode) { + let anchor = null + if ( + __FEATURE_SUSPENSE__ && + anchorVnode.component && + anchorVnode.component.asyncDep && + !anchorVnode.component.asyncResolved + ) { + anchor = anchorVnode.component.subTree.el + } else { + anchor = anchorVnode.el + } + return anchor +} + function locateNonHydratedAsyncRoot( instance: ComponentInternalInstance, ): ComponentInternalInstance | undefined { From 0b8521e86c53e4113f39461ffef990a0176f728d Mon Sep 17 00:00:00 2001 From: linzhe Date: Thu, 3 Jul 2025 22:36:56 +0800 Subject: [PATCH 4/7] chore: update test case --- .../__tests__/components/Suspense.spec.ts | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/packages/runtime-core/__tests__/components/Suspense.spec.ts b/packages/runtime-core/__tests__/components/Suspense.spec.ts index 65e801de277..563c91a179d 100644 --- a/packages/runtime-core/__tests__/components/Suspense.spec.ts +++ b/packages/runtime-core/__tests__/components/Suspense.spec.ts @@ -2230,5 +2230,57 @@ describe('Suspense', () => { fallback: [h('div'), h('div')], }) }) + + // #13559 + test('renders multiple async components in Suspense with v-for and updates on items change', async () => { + const CompAsyncSetup = defineAsyncComponent({ + props: ['item'], + render(ctx: any) { + return h('div', ctx.item.name) + }, + }) + + const items = ref([ + { id: 1, name: '111' }, + { id: 2, name: '222' }, + { id: 3, name: '333' }, + ]) + + const Comp = { + setup() { + return () => + h(Suspense, null, { + default: () => + h( + Fragment, + null, + items.value.map(item => + h(CompAsyncSetup, { item, key: item.id }), + ), + ), + }) + }, + } + + const root = nodeOps.createElement('div') + render(h(Comp), root) + await nextTick() + await Promise.all(deps) + + expect(serializeInner(root)).toBe( + `
111
222
333
`, + ) + + items.value = [ + { id: 4, name: '444' }, + { id: 5, name: '555' }, + { id: 6, name: '666' }, + ] + await nextTick() + await Promise.all(deps) + expect(serializeInner(root)).toBe( + `
444
555
666
`, + ) + }) }) }) From f7238e20b17590d35cf513057d77ae875038c62b Mon Sep 17 00:00:00 2001 From: linzhe141 <1572213544@qq.com> Date: Fri, 4 Jul 2025 09:28:15 +0800 Subject: [PATCH 5/7] chore: update --- packages/runtime-core/src/renderer.ts | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index fca76026a30..489904faac9 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -1226,6 +1226,7 @@ function baseCreateRenderer( if (!initialVNode.el) { const placeholder = (instance.subTree = createVNode(Comment)) processCommentNode(null, placeholder, container!, anchor) + initialVNode.el = placeholder.el } } else { setupRenderEffect( @@ -1980,9 +1981,7 @@ function baseCreateRenderer( const nextIndex = s2 + i const nextChild = c2[nextIndex] as VNode const anchor = - nextIndex + 1 < l2 - ? resolveInsertionAnchor(c2[nextIndex + 1] as VNode) - : parentAnchor + nextIndex + 1 < l2 ? (c2[nextIndex + 1] as VNode).el : parentAnchor if (newIndexToOldIndexMap[i] === 0) { // mount new patch( @@ -2568,21 +2567,6 @@ function getSequence(arr: number[]): number[] { return result } -function resolveInsertionAnchor(anchorVnode: VNode) { - let anchor = null - if ( - __FEATURE_SUSPENSE__ && - anchorVnode.component && - anchorVnode.component.asyncDep && - !anchorVnode.component.asyncResolved - ) { - anchor = anchorVnode.component.subTree.el - } else { - anchor = anchorVnode.el - } - return anchor -} - function locateNonHydratedAsyncRoot( instance: ComponentInternalInstance, ): ComponentInternalInstance | undefined { From 21e14077a15cdbc3a1816e57a14c01975ef6430e Mon Sep 17 00:00:00 2001 From: linzhe141 <1572213544@qq.com> Date: Fri, 4 Jul 2025 16:43:39 +0800 Subject: [PATCH 6/7] chore: update --- packages/runtime-core/src/renderer.ts | 7 +++++-- packages/runtime-core/src/vnode.ts | 7 +++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index 489904faac9..320800eebf3 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -1226,7 +1226,7 @@ function baseCreateRenderer( if (!initialVNode.el) { const placeholder = (instance.subTree = createVNode(Comment)) processCommentNode(null, placeholder, container!, anchor) - initialVNode.el = placeholder.el + initialVNode.placeholderEl = placeholder.el } } else { setupRenderEffect( @@ -1980,8 +1980,11 @@ function baseCreateRenderer( for (i = toBePatched - 1; i >= 0; i--) { const nextIndex = s2 + i const nextChild = c2[nextIndex] as VNode + const anchorVNode = c2[nextIndex + 1] as VNode const anchor = - nextIndex + 1 < l2 ? (c2[nextIndex + 1] as VNode).el : parentAnchor + nextIndex + 1 < l2 + ? anchorVNode.el || anchorVNode.placeholderEl + : parentAnchor if (newIndexToOldIndexMap[i] === 0) { // mount new patch( diff --git a/packages/runtime-core/src/vnode.ts b/packages/runtime-core/src/vnode.ts index a8c5340cd1f..a2735ffa380 100644 --- a/packages/runtime-core/src/vnode.ts +++ b/packages/runtime-core/src/vnode.ts @@ -217,6 +217,11 @@ export interface VNode< */ ssFallback: VNode | null + /** + * @internal + */ + placeholderEl: HostNode | null + // optimization only shapeFlag: number patchFlag: number @@ -711,6 +716,8 @@ export function cloneVNode( suspense: vnode.suspense, ssContent: vnode.ssContent && cloneVNode(vnode.ssContent), ssFallback: vnode.ssFallback && cloneVNode(vnode.ssFallback), + placeholderEl: vnode.placeholderEl, + el: vnode.el, anchor: vnode.anchor, ctx: vnode.ctx, From e23b6905d17845feb242dc550c95b013979477b5 Mon Sep 17 00:00:00 2001 From: daiwei Date: Sat, 5 Jul 2025 08:38:14 +0800 Subject: [PATCH 7/7] chore: minor tweaks --- packages/runtime-core/src/renderer.ts | 5 +++-- packages/runtime-core/src/vnode.ts | 8 ++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index 320800eebf3..f046e93ad85 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -1226,7 +1226,7 @@ function baseCreateRenderer( if (!initialVNode.el) { const placeholder = (instance.subTree = createVNode(Comment)) processCommentNode(null, placeholder, container!, anchor) - initialVNode.placeholderEl = placeholder.el + initialVNode.placeholder = placeholder.el } } else { setupRenderEffect( @@ -1983,7 +1983,8 @@ function baseCreateRenderer( const anchorVNode = c2[nextIndex + 1] as VNode const anchor = nextIndex + 1 < l2 - ? anchorVNode.el || anchorVNode.placeholderEl + ? // #13559, fallback to el placeholder for unresolved async component + anchorVNode.el || anchorVNode.placeholder : parentAnchor if (newIndexToOldIndexMap[i] === 0) { // mount new diff --git a/packages/runtime-core/src/vnode.ts b/packages/runtime-core/src/vnode.ts index a2735ffa380..cd1ef948d73 100644 --- a/packages/runtime-core/src/vnode.ts +++ b/packages/runtime-core/src/vnode.ts @@ -196,6 +196,7 @@ export interface VNode< // DOM el: HostNode | null + placeholder: HostNode | null // async component el placeholder anchor: HostNode | null // fragment anchor target: HostElement | null // teleport target targetStart: HostNode | null // teleport target start anchor @@ -217,11 +218,6 @@ export interface VNode< */ ssFallback: VNode | null - /** - * @internal - */ - placeholderEl: HostNode | null - // optimization only shapeFlag: number patchFlag: number @@ -716,7 +712,7 @@ export function cloneVNode( suspense: vnode.suspense, ssContent: vnode.ssContent && cloneVNode(vnode.ssContent), ssFallback: vnode.ssFallback && cloneVNode(vnode.ssFallback), - placeholderEl: vnode.placeholderEl, + placeholder: vnode.placeholder, el: vnode.el, anchor: vnode.anchor,