wip: get instance from rawProps to fix proxy handler caching

This commit is contained in:
Evan You 2024-12-06 21:08:24 +08:00
parent f6f3f14a3e
commit 238d1817cc
No known key found for this signature in database
GPG Key ID: 00E9AB7A6704CE0A
2 changed files with 65 additions and 39 deletions

View 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,

View 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])
}