Skip to content

Commit

Permalink
fix(runtime-core): use same internal object mechanism for slots
Browse files Browse the repository at this point in the history
close #10709
  • Loading branch information
yyx990803 committed Apr 16, 2024
1 parent 6930e60 commit 6df53d8
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 15 deletions.
10 changes: 2 additions & 8 deletions packages/runtime-core/src/componentProps.ts
Expand Up @@ -38,6 +38,7 @@ import { createPropsDefaultThis } from './compat/props'
import { isCompatEnabled, softAssertCompatEnabled } from './compat/compatConfig'
import { DeprecationTypes } from './compat/compatConfig'
import { shouldSkipAttr } from './compat/attrsFallthrough'
import { createInternalObject } from './internalObject'

export type ComponentPropsOptions<P = Data> =
| ComponentObjectPropsOptions<P>
Expand Down Expand Up @@ -185,21 +186,14 @@ type NormalizedProp =
export type NormalizedProps = Record<string, NormalizedProp>
export type NormalizedPropsOptions = [NormalizedProps, string[]] | []

/**
* Used during vnode props normalization to check if the vnode props is the
* attrs object of a component via `Object.getPrototypeOf`. This is more
* performant than defining a non-enumerable property.
*/
export const attrsProto = {}

export function initProps(
instance: ComponentInternalInstance,
rawProps: Data | null,
isStateful: number, // result of bitwise flag comparison
isSSR = false,
) {
const props: Data = {}
const attrs: Data = Object.create(attrsProto)
const attrs: Data = createInternalObject()

instance.propsDefaults = Object.create(null)

Expand Down
5 changes: 3 additions & 2 deletions packages/runtime-core/src/componentSlots.ts
Expand Up @@ -24,6 +24,7 @@ import { DeprecationTypes, isCompatEnabled } from './compat/compatConfig'
import { toRaw } from '@vue/reactivity'
import { trigger } from '@vue/reactivity'
import { TriggerOpTypes } from '@vue/reactivity'
import { createInternalObject } from './internalObject'

export type Slot<T extends any = any> = (
...args: IfAny<T, any[], [T] | (T extends undefined ? [] : never)>
Expand Down Expand Up @@ -177,12 +178,12 @@ export const initSlots = (
} else {
normalizeObjectSlots(
children as RawSlots,
(instance.slots = {}),
(instance.slots = createInternalObject()),
instance,
)
}
} else {
instance.slots = {}
instance.slots = createInternalObject()
if (children) {
normalizeVNodeSlots(instance, children)
}
Expand Down
12 changes: 12 additions & 0 deletions packages/runtime-core/src/internalObject.ts
@@ -0,0 +1,12 @@
/**
* Used during vnode props/slots normalization to check if the vnode props/slots
* are the internal attrs / slots object of a component via
* `Object.getPrototypeOf`. This is more performant than defining a
* non-enumerable property. (one of the optimizations done for ssr-benchmark)
*/
const internalObjectProto = Object.create(null)

This comment has been minimized.

Copy link
@jadepam

jadepam Apr 24, 2024

why not "Object.create({})"
鎴睆2024-04-24 17 20 34

This comment has been minimized.

Copy link
@yyx990803

yyx990803 Apr 24, 2024

Author Member

Good point, the original intention is to avoid properties on Object.prototype to show up, but this is probably an unintentional breaking change for code that previously relied on hasOwnProperty.


export const createInternalObject = () => Object.create(internalObjectProto)

export const isInternalObject = (obj: object) =>
Object.getPrototypeOf(obj) === internalObjectProto
8 changes: 3 additions & 5 deletions packages/runtime-core/src/vnode.ts
Expand Up @@ -55,7 +55,7 @@ import { convertLegacyVModelProps } from './compat/componentVModel'
import { defineLegacyVNodeProperties } from './compat/renderFn'
import { ErrorCodes, callWithAsyncErrorHandling } from './errorHandling'
import type { ComponentPublicInstance } from './componentPublicInstance'
import { attrsProto } from './componentProps'
import { isInternalObject } from './internalObject'

export const Fragment = Symbol.for('v-fgt') as any as {
__isFragment: true
Expand Down Expand Up @@ -617,9 +617,7 @@ function _createVNode(

export function guardReactiveProps(props: (Data & VNodeProps) | null) {
if (!props) return null
return isProxy(props) || Object.getPrototypeOf(props) === attrsProto
? extend({}, props)
: props
return isProxy(props) || isInternalObject(props) ? extend({}, props) : props
}

export function cloneVNode<T, U>(
Expand Down Expand Up @@ -791,7 +789,7 @@ export function normalizeChildren(vnode: VNode, children: unknown) {
} else {
type = ShapeFlags.SLOTS_CHILDREN
const slotFlag = (children as RawSlots)._
if (!slotFlag) {
if (!slotFlag && !isInternalObject(children)) {
// if slots are not normalized, attach context instance
// (compiled / normalized slots already have context)
;(children as RawSlots)._ctx = currentRenderingInstance
Expand Down

0 comments on commit 6df53d8

Please sign in to comment.