]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(runtime-core): use same internal object mechanism for slots
authorEvan You <yyx990803@gmail.com>
Tue, 16 Apr 2024 14:47:24 +0000 (22:47 +0800)
committerEvan You <yyx990803@gmail.com>
Tue, 16 Apr 2024 14:47:24 +0000 (22:47 +0800)
close #10709

packages/runtime-core/src/componentProps.ts
packages/runtime-core/src/componentSlots.ts
packages/runtime-core/src/internalObject.ts [new file with mode: 0644]
packages/runtime-core/src/vnode.ts

index 1c87304185c9b5623b0472dc93df1a7f393b4fe8..5a4292b6f36d8630f0b23bf23c2399ac8ad52677 100644 (file)
@@ -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>
@@ -185,13 +186,6 @@ 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,
@@ -199,7 +193,7 @@ export function initProps(
   isSSR = false,
 ) {
   const props: Data = {}
-  const attrs: Data = Object.create(attrsProto)
+  const attrs: Data = createInternalObject()
 
   instance.propsDefaults = Object.create(null)
 
index e0f051b39840db9b30fc4f3f84e3cedbc24771eb..66a09e5fa1a6765b734cbe39c6c34af7fead2af5 100644 (file)
@@ -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)>
@@ -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)
     }
diff --git a/packages/runtime-core/src/internalObject.ts b/packages/runtime-core/src/internalObject.ts
new file mode 100644 (file)
index 0000000..0c0c39b
--- /dev/null
@@ -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)
+
+export const createInternalObject = () => Object.create(internalObjectProto)
+
+export const isInternalObject = (obj: object) =>
+  Object.getPrototypeOf(obj) === internalObjectProto
index 28b60be78f25d273bf4d9cbacdfd5e94f8e50a4f..a1a6a908d2ae116a6eb2931ad74c1a7814cbf877 100644 (file)
@@ -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
@@ -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>(
@@ -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