]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
perf: optimize component props/slots internal object checks
authorEvan You <yyx990803@gmail.com>
Fri, 12 Apr 2024 06:41:03 +0000 (14:41 +0800)
committerEvan You <yyx990803@gmail.com>
Fri, 12 Apr 2024 06:41:03 +0000 (14:41 +0800)
packages/runtime-core/src/componentProps.ts
packages/runtime-core/src/componentSlots.ts
packages/runtime-core/src/vnode.ts

index 2d91affe0825a976336c2fae614b4de48f6b7af7..c0cef2f0901b651586291453998d049c78aa05cb 100644 (file)
@@ -12,7 +12,6 @@ import {
   PatchFlags,
   camelize,
   capitalize,
-  def,
   extend,
   hasOwn,
   hyphenate,
@@ -34,7 +33,6 @@ import {
   setCurrentInstance,
 } from './component'
 import { isEmitListener } from './componentEmits'
-import { InternalObjectKey } from './vnode'
 import type { AppContext } from './apiCreateApp'
 import { createPropsDefaultThis } from './compat/props'
 import { isCompatEnabled, softAssertCompatEnabled } from './compat/compatConfig'
@@ -187,6 +185,13 @@ 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,
@@ -194,8 +199,7 @@ export function initProps(
   isSSR = false,
 ) {
   const props: Data = {}
-  const attrs: Data = {}
-  def(attrs, InternalObjectKey, 1)
+  const attrs: Data = Object.create(attrsProto)
 
   instance.propsDefaults = Object.create(null)
 
index 61e1ecc072c1f07597ad7a91b9dfe18ca571994b..e0f051b39840db9b30fc4f3f84e3cedbc24771eb 100644 (file)
@@ -1,6 +1,5 @@
 import { type ComponentInternalInstance, currentInstance } from './component'
 import {
-  InternalObjectKey,
   type VNode,
   type VNodeChild,
   type VNodeNormalizedChildren,
@@ -174,7 +173,7 @@ export const initSlots = (
       // we should avoid the proxy object polluting the slots of the internal instance
       instance.slots = toRaw(children as InternalSlots)
       // make compiler marker non-enumerable
-      def(children as InternalSlots, '_', type)
+      def(instance.slots, '_', type)
     } else {
       normalizeObjectSlots(
         children as RawSlots,
@@ -188,7 +187,6 @@ export const initSlots = (
       normalizeVNodeSlots(instance, children)
     }
   }
-  def(instance.slots, InternalObjectKey, 1)
 }
 
 export const updateSlots = (
index daa9413d2ee704cbf5b954d25dc4310b6680a40c..28b60be78f25d273bf4d9cbacdfd5e94f8e50a4f 100644 (file)
@@ -55,6 +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'
 
 export const Fragment = Symbol.for('v-fgt') as any as {
   __isFragment: true
@@ -404,8 +405,6 @@ const createVNodeWithArgsTransform = (
   )
 }
 
-export const InternalObjectKey = `__vInternal`
-
 const normalizeKey = ({ key }: VNodeProps): VNode['key'] =>
   key != null ? key : null
 
@@ -618,7 +617,7 @@ function _createVNode(
 
 export function guardReactiveProps(props: (Data & VNodeProps) | null) {
   if (!props) return null
-  return isProxy(props) || InternalObjectKey in props
+  return isProxy(props) || Object.getPrototypeOf(props) === attrsProto
     ? extend({}, props)
     : props
 }
@@ -792,7 +791,7 @@ export function normalizeChildren(vnode: VNode, children: unknown) {
     } else {
       type = ShapeFlags.SLOTS_CHILDREN
       const slotFlag = (children as RawSlots)._
-      if (!slotFlag && !(InternalObjectKey in children!)) {
+      if (!slotFlag) {
         // if slots are not normalized, attach context instance
         // (compiled / normalized slots already have context)
         ;(children as RawSlots)._ctx = currentRenderingInstance