From 238d1817ccdd1b877bdf64a92d5c7d0973dfc319 Mon Sep 17 00:00:00 2001 From: Evan You Date: Fri, 6 Dec 2024 21:08:24 +0800 Subject: [PATCH] wip: get instance from rawProps to fix proxy handler caching --- packages/runtime-vapor/src/component.ts | 33 +++++++-- packages/runtime-vapor/src/componentProps.ts | 71 +++++++++++--------- 2 files changed, 65 insertions(+), 39 deletions(-) diff --git a/packages/runtime-vapor/src/component.ts b/packages/runtime-vapor/src/component.ts index 711c40294..251ad75ba 100644 --- a/packages/runtime-vapor/src/component.ts +++ b/packages/runtime-vapor/src/component.ts @@ -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 attrs: Record + slots: Record exposed: Record | null emitted: Record | 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 { } } +/** + * 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, diff --git a/packages/runtime-vapor/src/componentProps.ts b/packages/runtime-vapor/src/componentProps.ts index e9336b5ed..9410982d9 100644 --- a/packages/runtime-vapor/src/componentProps.ts +++ b/packages/runtime-vapor/src/componentProps.ts @@ -13,6 +13,7 @@ import { normalizeEmitsOptions } from './componentEmits' import { renderEffect } from './renderEffect' export type RawProps = Record 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 | null, ProxyHandler] { +): [ + ProxyHandler | null, + ProxyHandler, +] { 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) + } satisfies ProxyHandler) : 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 + } satisfies ProxyHandler return (comp.__propsHandlers = [propsHandlers, attrsHandlers]) }