Skip to content

Commit 2d79862

Browse files
committed
refactor: move async component resolution rendering logic from Suspense to renderer-specific registerDep callbacks.
1 parent 1df5e3b commit 2d79862

File tree

3 files changed

+65
-69
lines changed

3 files changed

+65
-69
lines changed

packages/runtime-core/src/components/Suspense.ts

Lines changed: 8 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,19 @@ import {
1111
openBlock,
1212
} from '../vnode'
1313
import { ShapeFlags, isArray, isFunction, toNumber } from '@vue/shared'
14-
import { type ComponentInternalInstance, handleSetupResult } from '../component'
14+
import type { ComponentInternalInstance } from '../component'
1515
import type { Slots } from '../componentSlots'
1616
import {
1717
type ElementNamespace,
1818
MoveType,
1919
type RendererElement,
2020
type RendererInternals,
2121
type RendererNode,
22-
type SetupRenderEffectFn,
2322
queuePostRenderEffect,
2423
} from '../renderer'
2524
import { queuePostFlushCb } from '../scheduler'
2625
import { filterSingleRoot, updateHOCHostEl } from '../componentRenderUtils'
27-
import {
28-
assertNumber,
29-
popWarningContext,
30-
pushWarningContext,
31-
warn,
32-
} from '../warning'
26+
import { assertNumber, warn } from '../warning'
3327
import { ErrorCodes, handleError } from '../errorHandling'
3428
import { NULL_DYNAMIC_COMPONENT } from '../helpers/resolveAssets'
3529

@@ -437,8 +431,7 @@ export interface SuspenseBoundary {
437431
next(): RendererNode | null
438432
registerDep(
439433
instance: ComponentInternalInstance,
440-
setupRenderEffect: SetupRenderEffectFn,
441-
optimized: boolean,
434+
onResolve: (setupResult: unknown) => void,
442435
): void
443436
unmount(parentSuspense: SuspenseBoundary | null, doRemove?: boolean): void
444437
}
@@ -474,7 +467,7 @@ function createSuspenseBoundary(
474467
m: move,
475468
um: unmount,
476469
n: next,
477-
o: { parentNode, remove },
470+
o: { parentNode },
478471
} = rendererInternals
479472

480473
// if set `suspensible: true`, set the current suspense as a dep of parent suspense
@@ -701,12 +694,12 @@ function createSuspenseBoundary(
701694
return suspense.activeBranch && next(suspense.activeBranch)
702695
},
703696

704-
registerDep(instance, setupRenderEffect, optimized) {
697+
registerDep(instance, onResolve) {
705698
const isInPendingSuspense = !!suspense.pendingBranch
706699
if (isInPendingSuspense) {
707700
suspense.deps++
708701
}
709-
const hydratedEl = instance.vapor ? null : instance.vnode.el
702+
710703
instance
711704
.asyncDep!.catch(err => {
712705
handleError(err, instance, ErrorCodes.SETUP_FUNCTION)
@@ -723,46 +716,8 @@ function createSuspenseBoundary(
723716
}
724717
// retry from this component
725718
instance.asyncResolved = true
726-
// vapor component
727-
if (instance.vapor) {
728-
// @ts-expect-error
729-
setupRenderEffect(asyncSetupResult)
730-
} else {
731-
const { vnode } = instance
732-
if (__DEV__) {
733-
pushWarningContext(vnode)
734-
}
735-
handleSetupResult(instance, asyncSetupResult, false)
736-
if (hydratedEl) {
737-
// vnode may have been replaced if an update happened before the
738-
// async dep is resolved.
739-
vnode.el = hydratedEl
740-
}
741-
const placeholder = !hydratedEl && instance.subTree.el
742-
setupRenderEffect(
743-
instance,
744-
vnode,
745-
// component may have been moved before resolve.
746-
// if this is not a hydration, instance.subTree will be the comment
747-
// placeholder.
748-
parentNode(hydratedEl || instance.subTree.el!)!,
749-
// anchor will not be used if this is hydration, so only need to
750-
// consider the comment placeholder case.
751-
hydratedEl ? null : next(instance.subTree),
752-
suspense,
753-
namespace,
754-
optimized,
755-
)
756-
if (placeholder) {
757-
// clean up placeholder reference
758-
vnode.placeholder = null
759-
remove(placeholder)
760-
}
761-
updateHOCHostEl(instance, vnode.el)
762-
if (__DEV__) {
763-
popWarningContext()
764-
}
765-
}
719+
onResolve(asyncSetupResult)
720+
766721
// only decrease deps count if suspense is not already resolved
767722
if (isInPendingSuspense && --suspense.deps === 0) {
768723
suspense.resolve()

packages/runtime-core/src/renderer.ts

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
type LifecycleHook,
2525
createComponentInstance,
2626
getComponentPublicInstance,
27+
handleSetupResult,
2728
setupComponent,
2829
} from './component'
2930
import {
@@ -1273,9 +1274,45 @@ function baseCreateRenderer(
12731274
// setup() is async. This component relies on async logic to be resolved
12741275
// before proceeding
12751276
if (__FEATURE_SUSPENSE__ && instance.asyncDep) {
1276-
parentSuspense &&
1277-
parentSuspense.registerDep(instance, setupRenderEffect, optimized)
1278-
1277+
if (parentSuspense) {
1278+
const hydratedEl = instance.vnode.el
1279+
parentSuspense.registerDep(instance, setupResult => {
1280+
const { vnode } = instance
1281+
if (__DEV__) {
1282+
pushWarningContext(vnode)
1283+
}
1284+
handleSetupResult(instance, setupResult, false)
1285+
if (hydratedEl) {
1286+
// vnode may have been replaced if an update happened before the
1287+
// async dep is resolved.
1288+
vnode.el = hydratedEl
1289+
}
1290+
const placeholder = !hydratedEl && instance.subTree.el
1291+
setupRenderEffect(
1292+
instance,
1293+
vnode,
1294+
// component may have been moved before resolve.
1295+
// if this is not a hydration, instance.subTree will be the comment
1296+
// placeholder.
1297+
hostParentNode(hydratedEl || instance.subTree.el!)!,
1298+
// anchor will not be used if this is hydration, so only need to
1299+
// consider the comment placeholder case.
1300+
hydratedEl ? null : getNextHostNode(instance.subTree),
1301+
parentSuspense,
1302+
namespace,
1303+
optimized,
1304+
)
1305+
if (placeholder) {
1306+
// clean up placeholder reference
1307+
vnode.placeholder = null
1308+
hostRemove(placeholder)
1309+
}
1310+
updateHOCHostEl(instance, vnode.el)
1311+
if (__DEV__) {
1312+
popWarningContext()
1313+
}
1314+
})
1315+
}
12791316
// Give it a placeholder if this is not hydration
12801317
// TODO handle self-defined fallback
12811318
if (!initialVNode.el) {

packages/runtime-vapor/src/component.ts

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -775,19 +775,15 @@ export function mountComponent(
775775
!instance.asyncResolved
776776
) {
777777
const component = instance.type
778-
instance.suspense.registerDep(
779-
instance as any,
780-
(setupResult: any) => {
781-
handleSetupResult(
782-
setupResult,
783-
component,
784-
instance,
785-
isFunction(component) ? component : component.setup,
786-
)
787-
mountComponent(instance, parent, anchor)
788-
},
789-
false,
790-
)
778+
instance.suspense.registerDep(instance as any, setupResult => {
779+
handleSetupResult(
780+
setupResult,
781+
component,
782+
instance,
783+
isFunction(component) ? component : component.setup,
784+
)
785+
mountComponent(instance, parent, anchor)
786+
})
791787
return
792788
}
793789

@@ -932,6 +928,10 @@ function handleSetupResult(
932928
instance: VaporComponentInstance,
933929
setupFn: VaporSetupFn | undefined,
934930
) {
931+
if (__DEV__) {
932+
pushWarningContext(instance)
933+
}
934+
935935
if (__DEV__ && !isBlock(setupResult)) {
936936
if (isFunction(component)) {
937937
warn(`Functional vapor component must return a block directly.`)
@@ -994,4 +994,8 @@ function handleSetupResult(
994994
warnExtraneousAttributes(instance.attrs)
995995
}
996996
}
997+
998+
if (__DEV__) {
999+
popWarningContext()
1000+
}
9971001
}

0 commit comments

Comments
 (0)