From 5df0b5f0a713065dfc7ca9649ed9b1a8cfda4dea Mon Sep 17 00:00:00 2001 From: edison1105 Date: Sat, 6 Apr 2024 10:03:03 +0800 Subject: [PATCH 1/2] fix(runtime-core): suspense content inherit scopeId --- 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 c7dfbf45dd2..f248e2a7dee 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -54,6 +54,7 @@ import { setRef } from './rendererTemplateRef' import { type SuspenseBoundary, type SuspenseImpl, + isSuspense, queueEffectWithSuspense, } from './components/Suspense' import type { TeleportImpl, TeleportVNode } from './components/Teleport' @@ -752,7 +753,11 @@ function baseCreateRenderer( subTree = filterSingleRoot(subTree.children as VNodeArrayChildren) || subTree } - if (vnode === subTree) { + if ( + vnode === subTree || + (isSuspense(subTree.type) && + (subTree.ssContent === vnode || subTree.ssFallback === vnode)) + ) { const parentVNode = parentComponent.vnode setScopeId( el, From 9136b87876121b510eabf72370815a08660cb158 Mon Sep 17 00:00:00 2001 From: edison1105 Date: Sun, 7 Apr 2024 21:15:19 +0800 Subject: [PATCH 2/2] test: add test case --- .../runtime-core/__tests__/scopeId.spec.ts | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/packages/runtime-core/__tests__/scopeId.spec.ts b/packages/runtime-core/__tests__/scopeId.spec.ts index 08753e023a1..d9a7d4dbfa4 100644 --- a/packages/runtime-core/__tests__/scopeId.spec.ts +++ b/packages/runtime-core/__tests__/scopeId.spec.ts @@ -1,5 +1,6 @@ import { Fragment, + Suspense, createBlock, createCommentVNode, createVNode, @@ -47,6 +48,49 @@ describe('scopeId runtime support', () => { ) }) + // #5148 + test('should attach scopeId to suspense content', async () => { + const deps: Promise[] = [] + const Child = { + async setup() { + const p = new Promise(r => setTimeout(r, 1)) + deps.push(p.then(() => Promise.resolve())) + + await p + return () => h('div', 'async') + }, + } + + const Wrapper = { + setup(_: any, { slots }: any) { + return () => slots.default({ Component: h(Child) }) + }, + } + + const App = { + __scopeId: 'parent', + setup() { + return () => + h(Wrapper, null, { + default: withCtx(({ Component }: any) => + h(Suspense, null, { + default: h(Component), + fallback: h('div', 'fallback'), + }), + ), + }) + }, + } + + const root = nodeOps.createElement('div') + render(h(App), root) + expect(serializeInner(root)).toBe(`
fallback
`) + + await Promise.all(deps) + await nextTick() + expect(serializeInner(root)).toBe(`
async
`) + }) + // :slotted basic test('should work on slots', () => { const Child = {