]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
wip: get instance from rawProps to fix proxy handler caching
authorEvan You <evan@vuejs.org>
Fri, 6 Dec 2024 13:08:24 +0000 (21:08 +0800)
committerEvan You <evan@vuejs.org>
Fri, 6 Dec 2024 13:27:24 +0000 (21:27 +0800)
packages/runtime-vapor/src/component.ts
packages/runtime-vapor/src/componentProps.ts

index 711c402945e196b070bf8d1a9f28199ece274055..251ad75bace7e1e7efc99091b6b260d6c412930b 100644 (file)
@@ -32,6 +32,11 @@ import { renderEffect } from './renderEffect'
 import { emit, normalizeEmitsOptions } from './componentEmits'
 import { setStyle } from './dom/style'
 import { setClass, setDynamicProp } from './dom/prop'
+import {
+  type RawSlots,
+  type Slot,
+  getSlotsProxyHandlers,
+} from './componentSlots'
 
 export { currentInstance } from '@vue/runtime-dom'
 
@@ -170,9 +175,10 @@ export class VaporComponentInstance implements GenericComponentInstance {
 
   block: Block
   scope: EffectScope
-  rawProps: RawProps | undefined
+  rawProps: RawProps
   props: Record<string, any>
   attrs: Record<string, any>
+  slots: Record<string, Slot>
   exposed: Record<string, any> | null
 
   emitted: Record<string, boolean> | null
@@ -215,7 +221,7 @@ export class VaporComponentInstance implements GenericComponentInstance {
   propsOptions?: NormalizedPropsOptions
   emitsOptions?: ObjectEmitsOptions | null
 
-  constructor(comp: VaporComponent, rawProps?: RawProps) {
+  constructor(comp: VaporComponent, rawProps?: RawProps, rawSlots?: RawSlots) {
     this.vapor = true
     this.uid = nextUid()
     this.type = comp
@@ -240,12 +246,20 @@ export class VaporComponentInstance implements GenericComponentInstance {
         false
 
     // init props
-    const target = rawProps || EMPTY_OBJ
-    const handlers = getPropsProxyHandlers(comp, this)
-    this.rawProps = rawProps
-    this.props = comp.props ? new Proxy(target, handlers[0]!) : {}
-    this.attrs = new Proxy(target, handlers[1])
+    this.rawProps = rawProps || EMPTY_OBJ
     this.hasFallthrough = hasFallthroughAttrs(comp, rawProps)
+    if (rawProps || comp.props) {
+      const [propsHandlers, attrsHandlers] = getPropsProxyHandlers(comp)
+      this.props = comp.props ? new Proxy(this, propsHandlers!) : {}
+      this.attrs = new Proxy(this, attrsHandlers)
+    } else {
+      this.props = this.attrs = EMPTY_OBJ
+    }
+
+    // init slots
+    this.slots = rawSlots
+      ? new Proxy(rawSlots, getSlotsProxyHandlers(comp))
+      : EMPTY_OBJ
 
     if (__DEV__) {
       // validate props
@@ -281,6 +295,11 @@ export class SetupContext<E = EmitsOptions> {
   }
 }
 
+/**
+ * Used when a component cannot be resolved at compile time
+ * and needs rely on runtime resolution - where it might fallback to a plain
+ * element if the resolution fails.
+ */
 export function createComponentWithFallback(
   comp: VaporComponent | string,
   rawProps: RawProps | undefined,
index e9336b5ed83749c25a8fdc9a52562c53f2a63d76..9410982d9613d9b22ab7a68dad2225f12a65b01f 100644 (file)
@@ -13,6 +13,7 @@ import { normalizeEmitsOptions } from './componentEmits'
 import { renderEffect } from './renderEffect'
 
 export type RawProps = Record<string, () => unknown> & {
+  // generated by compiler for :[key]="x" or v-bind="x"
   $?: DynamicPropsSource[]
 }
 
@@ -27,12 +28,12 @@ export function resolveSource(
   return isFunction(source) ? source() : source
 }
 
-const passThrough = (val: any) => val
-
 export function getPropsProxyHandlers(
   comp: VaporComponent,
-  instance: VaporComponentInstance,
-): [ProxyHandler<RawProps> | null, ProxyHandler<RawProps>] {
+): [
+  ProxyHandler<VaporComponentInstance> | null,
+  ProxyHandler<VaporComponentInstance>,
+] {
   if (comp.__propsHandlers) {
     return comp.__propsHandlers
   }
@@ -44,23 +45,12 @@ export function getPropsProxyHandlers(
         key !== '$' && !isProp(key) && !isEmitListener(emitsOptions, key)
     : YES
 
-  const castProp = propsOptions
-    ? (value: any, key: string, isAbsent = false) =>
-        resolvePropValue(
-          propsOptions,
-          key as string,
-          value,
-          instance,
-          resolveDefault,
-          isAbsent,
-        )
-    : passThrough
-
-  const getProp = (target: RawProps, key: string) => {
+  const getProp = (instance: VaporComponentInstance, key: string) => {
     if (key === '$' || !isProp(key)) {
       return
     }
-    const dynamicSources = target.$
+    const rawProps = instance.rawProps
+    const dynamicSources = rawProps.$
     if (dynamicSources) {
       let i = dynamicSources.length
       let source, isDynamic, rawKey
@@ -70,17 +60,35 @@ export function getPropsProxyHandlers(
         source = isDynamic ? (source as Function)() : source
         for (rawKey in source) {
           if (camelize(rawKey) === key) {
-            return castProp(isDynamic ? source[rawKey] : source[rawKey](), key)
+            return resolvePropValue(
+              propsOptions!,
+              key,
+              isDynamic ? source[rawKey] : source[rawKey](),
+              instance,
+              resolveDefault,
+            )
           }
         }
       }
     }
-    for (const rawKey in target) {
+    for (const rawKey in rawProps) {
       if (camelize(rawKey) === key) {
-        return castProp(target[rawKey](), key)
+        return resolvePropValue(
+          propsOptions!,
+          key,
+          rawProps[rawKey](),
+          instance,
+          resolveDefault,
+        )
       }
     }
-    return castProp(undefined, key, true)
+    return resolvePropValue(
+      propsOptions!,
+      key,
+      undefined,
+      instance,
+      resolveDefault,
+    )
   }
 
   const propsHandlers = propsOptions
@@ -99,7 +107,7 @@ export function getPropsProxyHandlers(
         ownKeys: () => Object.keys(propsOptions),
         set: NO,
         deleteProperty: NO,
-      } satisfies ProxyHandler<RawProps>)
+      } satisfies ProxyHandler<VaporComponentInstance>)
     : null
 
   const getAttr = (target: RawProps, key: string) => {
@@ -142,25 +150,24 @@ export function getPropsProxyHandlers(
   }
 
   const attrsHandlers = {
-    get: (target, key: string) => {
-      return getAttr(target, key)
-    },
-    has: hasAttr,
+    get: (target, key: string) => getAttr(target.rawProps, key),
+    has: (target, key: string) => hasAttr(target.rawProps, key),
     getOwnPropertyDescriptor(target, key: string) {
-      if (hasAttr(target, key)) {
+      if (hasAttr(target.rawProps, key)) {
         return {
           configurable: true,
           enumerable: true,
-          get: () => getAttr(target, key),
+          get: () => getAttr(target.rawProps, key),
         }
       }
     },
     ownKeys(target) {
+      const rawProps = target.rawProps
       const keys: string[] = []
-      for (const key in target) {
+      for (const key in rawProps) {
         if (isAttr(key)) keys.push(key)
       }
-      const dynamicSources = target.$
+      const dynamicSources = rawProps.$
       if (dynamicSources) {
         let i = dynamicSources.length
         let source
@@ -175,7 +182,7 @@ export function getPropsProxyHandlers(
     },
     set: NO,
     deleteProperty: NO,
-  } satisfies ProxyHandler<RawProps>
+  } satisfies ProxyHandler<VaporComponentInstance>
 
   return (comp.__propsHandlers = [propsHandlers, attrsHandlers])
 }