From: Evan You Date: Wed, 4 Dec 2024 15:02:15 +0000 (+0800) Subject: wip: use proxy for static props too X-Git-Tag: v3.6.0-alpha.1~16^2~237 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=33d1b8bcec1a94733cecdb0d6b6a2abf98067c17;p=thirdparty%2Fvuejs%2Fcore.git wip: use proxy for static props too --- diff --git a/packages/runtime-vapor/src/component.ts b/packages/runtime-vapor/src/component.ts index d78ce73d09..d05f8ffbcf 100644 --- a/packages/runtime-vapor/src/component.ts +++ b/packages/runtime-vapor/src/component.ts @@ -16,11 +16,11 @@ import { } from '@vue/runtime-dom' import { type Block, isBlock } from './block' import { pauseTracking, resetTracking } from '@vue/reactivity' -import { EMPTY_OBJ, isFunction } from '@vue/shared' +import { EMPTY_OBJ, hasOwn, isFunction } from '@vue/shared' import { type RawProps, - getDynamicPropsHandlers, - initStaticProps, + getPropsProxyHandlers, + normalizePropsOptions, } from './componentProps' import { setDynamicProp } from './dom/prop' import { renderEffect } from './renderEffect' @@ -200,22 +200,30 @@ export class VaporComponentInstance implements GenericComponentInstance { this.rawProps = rawProps this.provides = this.refs = EMPTY_OBJ - this.emitted = this.ec = this.exposed = null + this.emitted = this.ec = this.exposed = this.propsDefaults = null this.isMounted = this.isUnmounted = this.isDeactivated = false // init props - this.propsDefaults = null + const target = rawProps || EMPTY_OBJ + const handlers = getPropsProxyHandlers(comp, this) + this.props = comp.props ? new Proxy(target, handlers[0]!) : {} + this.attrs = new Proxy(target, handlers[1]) + + // determine fallthrough this.hasFallthrough = false - if (rawProps && rawProps.$) { - // has dynamic props, use proxy - const handlers = getDynamicPropsHandlers(comp, this) - this.props = comp.props ? new Proxy(rawProps, handlers[0]!) : EMPTY_OBJ - this.attrs = new Proxy(rawProps, handlers[1]) - this.hasFallthrough = true - } else { - this.props = {} - this.attrs = {} - this.hasFallthrough = initStaticProps(comp, rawProps, this) + if (rawProps) { + if (rawProps.$) { + this.hasFallthrough = true + } else { + // check if rawProps contains any keys not declared + const propsOptions = normalizePropsOptions(comp)[0]! + for (const key in rawProps) { + if (!hasOwn(propsOptions, key)) { + this.hasFallthrough = true + break + } + } + } } // TODO validate props diff --git a/packages/runtime-vapor/src/componentProps.ts b/packages/runtime-vapor/src/componentProps.ts index 3d41085325..3ac42dbb30 100644 --- a/packages/runtime-vapor/src/componentProps.ts +++ b/packages/runtime-vapor/src/componentProps.ts @@ -1,4 +1,4 @@ -import { EMPTY_ARR, NO, camelize, hasOwn, isFunction } from '@vue/shared' +import { EMPTY_ARR, NO, hasOwn, isFunction } from '@vue/shared' import type { VaporComponent, VaporComponentInstance } from './component' import { type NormalizedPropsOptions, @@ -16,70 +16,6 @@ type DynamicPropsSource = | (() => Record) | Record unknown> -export function initStaticProps( - comp: VaporComponent, - rawProps: RawProps | undefined, - instance: VaporComponentInstance, -): boolean { - let hasAttrs = false - const { props, attrs } = instance - const [propsOptions, needCastKeys] = normalizePropsOptions(comp) - const emitsOptions = normalizeEmitsOptions(comp) - - // for dev emit check - if (__DEV__) { - instance.propsOptions = normalizePropsOptions(comp) - instance.emitsOptions = emitsOptions - } - - for (const key in rawProps) { - const normalizedKey = camelize(key) - const needCast = needCastKeys && needCastKeys.includes(normalizedKey) - const source = rawProps[key] - if (propsOptions && normalizedKey in propsOptions) { - Object.defineProperty(props, normalizedKey, { - enumerable: true, - get: needCast - ? () => - resolvePropValue( - propsOptions, - normalizedKey, - source(), - instance, - resolveDefault, - ) - : source, - }) - } else if (!isEmitListener(emitsOptions, key)) { - Object.defineProperty(attrs, key, { - enumerable: true, - get: source, - }) - hasAttrs = true - } - } - for (const key in propsOptions) { - if (!(key in props)) { - props[key] = resolvePropValue( - propsOptions, - key, - undefined, - instance, - resolveDefault, - true, - ) - } - } - return hasAttrs -} - -function resolveDefault( - factory: (props: Record) => unknown, - instance: VaporComponentInstance, -) { - return factory.call(null, instance.props) -} - // TODO optimization: maybe convert functions into computeds export function resolveSource( source: Record | (() => Record), @@ -89,41 +25,37 @@ export function resolveSource( const passThrough = (val: any) => val -export function getDynamicPropsHandlers( +export function getPropsProxyHandlers( comp: VaporComponent, instance: VaporComponentInstance, ): [ProxyHandler | null, ProxyHandler] { if (comp.__propsHandlers) { return comp.__propsHandlers } - let normalizedKeys: string[] | undefined const propsOptions = normalizePropsOptions(comp)[0] const emitsOptions = normalizeEmitsOptions(comp) const isProp = propsOptions ? (key: string) => hasOwn(propsOptions, key) : NO + const castProp = propsOptions + ? (key: string, value: any, isAbsent = false) => + resolvePropValue( + propsOptions, + key as string, + value, + instance, + resolveDefault, + isAbsent, + ) + : passThrough const getProp = (target: RawProps, key: string, asProp: boolean) => { - if (key === '$') return if (asProp) { - if (!isProp(key)) return + if (!isProp(key) || key === '$') return } else if (isProp(key) || isEmitListener(emitsOptions, key)) { return } - const castProp = propsOptions - ? (value: any, isAbsent = false) => - asProp - ? resolvePropValue( - propsOptions, - key as string, - value, - instance, - resolveDefault, - isAbsent, - ) - : value - : passThrough if (key in target) { - return castProp(target[key as string]()) + return castProp(key, target[key as string]()) } const dynamicSources = target.$ if (dynamicSources) { @@ -134,11 +66,11 @@ export function getDynamicPropsHandlers( isDynamic = isFunction(source) source = isDynamic ? (source as Function)() : source if (hasOwn(source, key)) { - return castProp(isDynamic ? source[key] : source[key]()) + return castProp(key, isDynamic ? source[key] : source[key]()) } } } - return castProp(undefined, true) + return castProp(key, undefined, true) } const propsHandlers = propsOptions @@ -154,8 +86,7 @@ export function getDynamicPropsHandlers( } } }, - ownKeys: () => - normalizedKeys || (normalizedKeys = Object.keys(propsOptions)), + ownKeys: () => Object.keys(propsOptions), set: NO, deleteProperty: NO, } satisfies ProxyHandler) @@ -207,7 +138,9 @@ export function getDynamicPropsHandlers( return (comp.__propsHandlers = [propsHandlers, attrsHandlers]) } -function normalizePropsOptions(comp: VaporComponent): NormalizedPropsOptions { +export function normalizePropsOptions( + comp: VaporComponent, +): NormalizedPropsOptions { const cached = comp.__propsOptions if (cached) return cached @@ -220,3 +153,10 @@ function normalizePropsOptions(comp: VaporComponent): NormalizedPropsOptions { return (comp.__propsOptions = [normalized, needCastKeys]) } + +function resolveDefault( + factory: (props: Record) => unknown, + instance: VaporComponentInstance, +) { + return factory.call(null, instance.props) +}