mirror of https://github.com/vuejs/core.git
Merge 58d97cd78a
into 56be3dd4db
This commit is contained in:
commit
b1dc06a882
|
@ -2,6 +2,7 @@ import {
|
||||||
Comment,
|
Comment,
|
||||||
type VNode,
|
type VNode,
|
||||||
type VNodeProps,
|
type VNodeProps,
|
||||||
|
cloneVNode,
|
||||||
closeBlock,
|
closeBlock,
|
||||||
createVNode,
|
createVNode,
|
||||||
currentBlock,
|
currentBlock,
|
||||||
|
@ -10,7 +11,14 @@ import {
|
||||||
normalizeVNode,
|
normalizeVNode,
|
||||||
openBlock,
|
openBlock,
|
||||||
} from '../vnode'
|
} from '../vnode'
|
||||||
import { ShapeFlags, isArray, isFunction, toNumber } from '@vue/shared'
|
import {
|
||||||
|
EMPTY_OBJ,
|
||||||
|
ShapeFlags,
|
||||||
|
extend,
|
||||||
|
isArray,
|
||||||
|
isFunction,
|
||||||
|
toNumber,
|
||||||
|
} from '@vue/shared'
|
||||||
import { type ComponentInternalInstance, handleSetupResult } from '../component'
|
import { type ComponentInternalInstance, handleSetupResult } from '../component'
|
||||||
import type { Slots } from '../componentSlots'
|
import type { Slots } from '../componentSlots'
|
||||||
import {
|
import {
|
||||||
|
@ -31,6 +39,7 @@ import {
|
||||||
} from '../warning'
|
} from '../warning'
|
||||||
import { ErrorCodes, handleError } from '../errorHandling'
|
import { ErrorCodes, handleError } from '../errorHandling'
|
||||||
import { NULL_DYNAMIC_COMPONENT } from '../helpers/resolveAssets'
|
import { NULL_DYNAMIC_COMPONENT } from '../helpers/resolveAssets'
|
||||||
|
import type { Writable } from '../../types/util'
|
||||||
|
|
||||||
export interface SuspenseProps {
|
export interface SuspenseProps {
|
||||||
onResolve?: () => void
|
onResolve?: () => void
|
||||||
|
@ -45,6 +54,14 @@ export interface SuspenseProps {
|
||||||
suspensible?: boolean
|
suspensible?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ComponentProps = [
|
||||||
|
'onFallback',
|
||||||
|
'onPending',
|
||||||
|
'onResolve',
|
||||||
|
'timeout',
|
||||||
|
'suspensible',
|
||||||
|
]
|
||||||
|
|
||||||
export const isSuspense = (type: any): boolean => type.__isSuspense
|
export const isSuspense = (type: any): boolean => type.__isSuspense
|
||||||
|
|
||||||
// incrementing unique id for every pending branch
|
// incrementing unique id for every pending branch
|
||||||
|
@ -820,11 +837,15 @@ function hydrateSuspense(
|
||||||
function normalizeSuspenseChildren(vnode: VNode): void {
|
function normalizeSuspenseChildren(vnode: VNode): void {
|
||||||
const { shapeFlag, children } = vnode
|
const { shapeFlag, children } = vnode
|
||||||
const isSlotChildren = shapeFlag & ShapeFlags.SLOTS_CHILDREN
|
const isSlotChildren = shapeFlag & ShapeFlags.SLOTS_CHILDREN
|
||||||
vnode.ssContent = normalizeSuspenseSlot(
|
const attrs = getFallthroughAttrs(vnode)
|
||||||
|
vnode.ssContent = cloneVNode(
|
||||||
|
normalizeSuspenseSlot(
|
||||||
isSlotChildren ? (children as Slots).default : children,
|
isSlotChildren ? (children as Slots).default : children,
|
||||||
|
),
|
||||||
|
attrs,
|
||||||
)
|
)
|
||||||
vnode.ssFallback = isSlotChildren
|
vnode.ssFallback = isSlotChildren
|
||||||
? normalizeSuspenseSlot((children as Slots).fallback)
|
? cloneVNode(normalizeSuspenseSlot((children as Slots).fallback), attrs)
|
||||||
: createVNode(Comment)
|
: createVNode(Comment)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -902,3 +923,35 @@ function isVNodeSuspensible(vnode: VNode) {
|
||||||
const suspensible = vnode.props && vnode.props.suspensible
|
const suspensible = vnode.props && vnode.props.suspensible
|
||||||
return suspensible != null && suspensible !== false
|
return suspensible != null && suspensible !== false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: The standard renderer should be abstracted to also allow Suspense to work, so
|
||||||
|
* Suspense can work as a normal component (like Transition and KeepAlive), instead of a "fake" one,
|
||||||
|
* as it currently is. This is why in some places special handling for it exists. Having it working
|
||||||
|
* as an standard component means that there's no need to re-implement all the handling of fallthrough attributes.
|
||||||
|
* Hence, this is just a workaround to normalize the behaviour across built-in components.
|
||||||
|
* See: https://github.com/vuejs/rfcs/discussions/664
|
||||||
|
*
|
||||||
|
* Suspense can receive fallthrough attributes from props and attrs
|
||||||
|
* - From props: When they are specified directly in the Suspense component (they're filtered here)
|
||||||
|
* - From attrs: When Suspense is a child of another component
|
||||||
|
*/
|
||||||
|
function getFallthroughAttrs(n2: VNode) {
|
||||||
|
const props = n2.props ?? EMPTY_OBJ
|
||||||
|
const fallthrough: Writable<typeof props> = {}
|
||||||
|
for (const key in props) {
|
||||||
|
if (!ComponentProps.includes(key)) {
|
||||||
|
fallthrough[key] = props[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
n2.suspense &&
|
||||||
|
n2.suspense.parentComponent &&
|
||||||
|
n2.suspense.parentComponent.attrs
|
||||||
|
) {
|
||||||
|
return extend({}, fallthrough, n2.suspense.parentComponent.attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fallthrough
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
export type Writable<T> = {
|
||||||
|
-readonly [P in keyof T]: T[P]
|
||||||
|
}
|
Loading…
Reference in New Issue