feat(runtime-core): improve component public instance proxy inspection
This commit is contained in:
parent
f42d11e8e1
commit
899287ad35
@ -108,8 +108,10 @@ describe('component: proxy', () => {
|
|||||||
expect(instanceProxy.$attrs).toBe(instance!.attrs)
|
expect(instanceProxy.$attrs).toBe(instance!.attrs)
|
||||||
expect(instanceProxy.$slots).toBe(instance!.slots)
|
expect(instanceProxy.$slots).toBe(instance!.slots)
|
||||||
expect(instanceProxy.$refs).toBe(instance!.refs)
|
expect(instanceProxy.$refs).toBe(instance!.refs)
|
||||||
expect(instanceProxy.$parent).toBe(instance!.parent)
|
expect(instanceProxy.$parent).toBe(
|
||||||
expect(instanceProxy.$root).toBe(instance!.root)
|
instance!.parent && instance!.parent.proxy
|
||||||
|
)
|
||||||
|
expect(instanceProxy.$root).toBe(instance!.root.proxy)
|
||||||
expect(instanceProxy.$emit).toBe(instance!.emit)
|
expect(instanceProxy.$emit).toBe(instance!.emit)
|
||||||
expect(instanceProxy.$el).toBe(instance!.vnode.el)
|
expect(instanceProxy.$el).toBe(instance!.vnode.el)
|
||||||
expect(instanceProxy.$options).toBe(instance!.type)
|
expect(instanceProxy.$options).toBe(instance!.type)
|
||||||
@ -174,6 +176,14 @@ describe('component: proxy', () => {
|
|||||||
// set non-existent (goes into sink)
|
// set non-existent (goes into sink)
|
||||||
instanceProxy.baz = 1
|
instanceProxy.baz = 1
|
||||||
expect('baz' in instanceProxy).toBe(true)
|
expect('baz' in instanceProxy).toBe(true)
|
||||||
|
|
||||||
|
// dev mode ownKeys check for console inspection
|
||||||
|
expect(Object.keys(instanceProxy)).toMatchObject([
|
||||||
|
'msg',
|
||||||
|
'bar',
|
||||||
|
'foo',
|
||||||
|
'baz'
|
||||||
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
// #864
|
// #864
|
||||||
|
@ -7,9 +7,13 @@ import {
|
|||||||
resetTracking
|
resetTracking
|
||||||
} from '@vue/reactivity'
|
} from '@vue/reactivity'
|
||||||
import {
|
import {
|
||||||
PublicInstanceProxyHandlers,
|
|
||||||
ComponentPublicInstance,
|
ComponentPublicInstance,
|
||||||
runtimeCompiledRenderProxyHandlers
|
ComponentPublicProxyTarget,
|
||||||
|
PublicInstanceProxyHandlers,
|
||||||
|
RuntimeCompiledPublicInstanceProxyHandlers,
|
||||||
|
createDevProxyTarget,
|
||||||
|
exposePropsOnDevProxyTarget,
|
||||||
|
exposeRenderContextOnDevProxyTarget
|
||||||
} from './componentProxy'
|
} from './componentProxy'
|
||||||
import { ComponentPropsOptions, resolveProps } from './componentProps'
|
import { ComponentPropsOptions, resolveProps } from './componentProps'
|
||||||
import { Slots, resolveSlots } from './componentSlots'
|
import { Slots, resolveSlots } from './componentSlots'
|
||||||
@ -139,6 +143,7 @@ export interface ComponentInternalInstance {
|
|||||||
attrs: Data
|
attrs: Data
|
||||||
slots: Slots
|
slots: Slots
|
||||||
proxy: ComponentPublicInstance | null
|
proxy: ComponentPublicInstance | null
|
||||||
|
proxyTarget: ComponentPublicProxyTarget
|
||||||
// alternative proxy used only for runtime-compiled render functions using
|
// alternative proxy used only for runtime-compiled render functions using
|
||||||
// `with` block
|
// `with` block
|
||||||
withProxy: ComponentPublicInstance | null
|
withProxy: ComponentPublicInstance | null
|
||||||
@ -195,12 +200,13 @@ export function createComponentInstance(
|
|||||||
parent,
|
parent,
|
||||||
appContext,
|
appContext,
|
||||||
type: vnode.type as Component,
|
type: vnode.type as Component,
|
||||||
root: null!, // set later so it can point to itself
|
root: null!, // to be immediately set
|
||||||
next: null,
|
next: null,
|
||||||
subTree: null!, // will be set synchronously right after creation
|
subTree: null!, // will be set synchronously right after creation
|
||||||
update: null!, // will be set synchronously right after creation
|
update: null!, // will be set synchronously right after creation
|
||||||
render: null,
|
render: null,
|
||||||
proxy: null,
|
proxy: null,
|
||||||
|
proxyTarget: null!, // to be immediately set
|
||||||
withProxy: null,
|
withProxy: null,
|
||||||
propsProxy: null,
|
propsProxy: null,
|
||||||
setupContext: null,
|
setupContext: null,
|
||||||
@ -250,6 +256,11 @@ export function createComponentInstance(
|
|||||||
ec: null,
|
ec: null,
|
||||||
emit: null as any // to be set immediately
|
emit: null as any // to be set immediately
|
||||||
}
|
}
|
||||||
|
if (__DEV__) {
|
||||||
|
instance.proxyTarget = createDevProxyTarget(instance)
|
||||||
|
} else {
|
||||||
|
instance.proxyTarget = { _: instance }
|
||||||
|
}
|
||||||
instance.root = parent ? parent.root : instance
|
instance.root = parent ? parent.root : instance
|
||||||
instance.emit = emit.bind(null, instance)
|
instance.emit = emit.bind(null, instance)
|
||||||
return instance
|
return instance
|
||||||
@ -325,7 +336,10 @@ function setupStatefulComponent(
|
|||||||
// 0. create render proxy property access cache
|
// 0. create render proxy property access cache
|
||||||
instance.accessCache = {}
|
instance.accessCache = {}
|
||||||
// 1. create public instance / render proxy
|
// 1. create public instance / render proxy
|
||||||
instance.proxy = new Proxy(instance, PublicInstanceProxyHandlers)
|
instance.proxy = new Proxy(instance.proxyTarget, PublicInstanceProxyHandlers)
|
||||||
|
if (__DEV__) {
|
||||||
|
exposePropsOnDevProxyTarget(instance)
|
||||||
|
}
|
||||||
// 2. create props proxy
|
// 2. create props proxy
|
||||||
// the propsProxy is a reactive AND readonly proxy to the actual props.
|
// the propsProxy is a reactive AND readonly proxy to the actual props.
|
||||||
// it will be updated in resolveProps() on updates before render
|
// it will be updated in resolveProps() on updates before render
|
||||||
@ -353,7 +367,7 @@ function setupStatefulComponent(
|
|||||||
if (isSSR) {
|
if (isSSR) {
|
||||||
// return the promise so server-renderer can wait on it
|
// return the promise so server-renderer can wait on it
|
||||||
return setupResult.then((resolvedResult: unknown) => {
|
return setupResult.then((resolvedResult: unknown) => {
|
||||||
handleSetupResult(instance, resolvedResult, parentSuspense, isSSR)
|
handleSetupResult(instance, resolvedResult, isSSR)
|
||||||
})
|
})
|
||||||
} else if (__FEATURE_SUSPENSE__) {
|
} else if (__FEATURE_SUSPENSE__) {
|
||||||
// async setup returned Promise.
|
// async setup returned Promise.
|
||||||
@ -366,7 +380,7 @@ function setupStatefulComponent(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
handleSetupResult(instance, setupResult, parentSuspense, isSSR)
|
handleSetupResult(instance, setupResult, isSSR)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
finishComponentSetup(instance, isSSR)
|
finishComponentSetup(instance, isSSR)
|
||||||
@ -376,7 +390,6 @@ function setupStatefulComponent(
|
|||||||
export function handleSetupResult(
|
export function handleSetupResult(
|
||||||
instance: ComponentInternalInstance,
|
instance: ComponentInternalInstance,
|
||||||
setupResult: unknown,
|
setupResult: unknown,
|
||||||
parentSuspense: SuspenseBoundary | null,
|
|
||||||
isSSR: boolean
|
isSSR: boolean
|
||||||
) {
|
) {
|
||||||
if (isFunction(setupResult)) {
|
if (isFunction(setupResult)) {
|
||||||
@ -392,6 +405,9 @@ export function handleSetupResult(
|
|||||||
// setup returned bindings.
|
// setup returned bindings.
|
||||||
// assuming a render function compiled from template is present.
|
// assuming a render function compiled from template is present.
|
||||||
instance.renderContext = reactive(setupResult)
|
instance.renderContext = reactive(setupResult)
|
||||||
|
if (__DEV__) {
|
||||||
|
exposeRenderContextOnDevProxyTarget(instance)
|
||||||
|
}
|
||||||
} else if (__DEV__ && setupResult !== undefined) {
|
} else if (__DEV__ && setupResult !== undefined) {
|
||||||
warn(
|
warn(
|
||||||
`setup() should return an object. Received: ${
|
`setup() should return an object. Received: ${
|
||||||
@ -460,8 +476,8 @@ function finishComponentSetup(
|
|||||||
// also only allows a whitelist of globals to fallthrough.
|
// also only allows a whitelist of globals to fallthrough.
|
||||||
if (instance.render._rc) {
|
if (instance.render._rc) {
|
||||||
instance.withProxy = new Proxy(
|
instance.withProxy = new Proxy(
|
||||||
instance,
|
instance.proxyTarget,
|
||||||
runtimeCompiledRenderProxyHandlers
|
RuntimeCompiledPublicInstanceProxyHandlers
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,9 +38,14 @@ import {
|
|||||||
import {
|
import {
|
||||||
reactive,
|
reactive,
|
||||||
ComputedGetter,
|
ComputedGetter,
|
||||||
WritableComputedOptions
|
WritableComputedOptions,
|
||||||
|
ComputedRef
|
||||||
} from '@vue/reactivity'
|
} from '@vue/reactivity'
|
||||||
import { ComponentObjectPropsOptions, ExtractPropTypes } from './componentProps'
|
import {
|
||||||
|
ComponentObjectPropsOptions,
|
||||||
|
ExtractPropTypes,
|
||||||
|
normalizePropsOptions
|
||||||
|
} from './componentProps'
|
||||||
import { EmitsOptions } from './componentEmits'
|
import { EmitsOptions } from './componentEmits'
|
||||||
import { Directive } from './directives'
|
import { Directive } from './directives'
|
||||||
import { ComponentPublicInstance } from './componentProxy'
|
import { ComponentPublicInstance } from './componentProxy'
|
||||||
@ -239,6 +244,7 @@ export function applyOptions(
|
|||||||
options: ComponentOptions,
|
options: ComponentOptions,
|
||||||
asMixin: boolean = false
|
asMixin: boolean = false
|
||||||
) {
|
) {
|
||||||
|
const proxyTarget = instance.proxyTarget
|
||||||
const ctx = instance.proxy!
|
const ctx = instance.proxy!
|
||||||
const {
|
const {
|
||||||
// composition
|
// composition
|
||||||
@ -277,7 +283,7 @@ export function applyOptions(
|
|||||||
|
|
||||||
const globalMixins = instance.appContext.mixins
|
const globalMixins = instance.appContext.mixins
|
||||||
// call it only during dev
|
// call it only during dev
|
||||||
const checkDuplicateProperties = __DEV__ ? createDuplicateChecker() : null
|
|
||||||
// applyOptions is called non-as-mixin once per instance
|
// applyOptions is called non-as-mixin once per instance
|
||||||
if (!asMixin) {
|
if (!asMixin) {
|
||||||
callSyncHook('beforeCreate', options, ctx, globalMixins)
|
callSyncHook('beforeCreate', options, ctx, globalMixins)
|
||||||
@ -293,8 +299,10 @@ export function applyOptions(
|
|||||||
applyMixins(instance, mixins)
|
applyMixins(instance, mixins)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const checkDuplicateProperties = __DEV__ ? createDuplicateChecker() : null
|
||||||
|
|
||||||
if (__DEV__ && propsOptions) {
|
if (__DEV__ && propsOptions) {
|
||||||
for (const key in propsOptions) {
|
for (const key in normalizePropsOptions(propsOptions)[0]) {
|
||||||
checkDuplicateProperties!(OptionTypes.PROPS, key)
|
checkDuplicateProperties!(OptionTypes.PROPS, key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -314,6 +322,7 @@ export function applyOptions(
|
|||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
for (const key in data) {
|
for (const key in data) {
|
||||||
checkDuplicateProperties!(OptionTypes.DATA, key)
|
checkDuplicateProperties!(OptionTypes.DATA, key)
|
||||||
|
if (!(key in proxyTarget)) proxyTarget[key] = data[key]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
instance.data = reactive(data)
|
instance.data = reactive(data)
|
||||||
@ -326,9 +335,6 @@ export function applyOptions(
|
|||||||
if (computedOptions) {
|
if (computedOptions) {
|
||||||
for (const key in computedOptions) {
|
for (const key in computedOptions) {
|
||||||
const opt = (computedOptions as ComputedOptions)[key]
|
const opt = (computedOptions as ComputedOptions)[key]
|
||||||
|
|
||||||
__DEV__ && checkDuplicateProperties!(OptionTypes.COMPUTED, key)
|
|
||||||
|
|
||||||
if (isFunction(opt)) {
|
if (isFunction(opt)) {
|
||||||
renderContext[key] = computed(opt.bind(ctx, ctx))
|
renderContext[key] = computed(opt.bind(ctx, ctx))
|
||||||
} else {
|
} else {
|
||||||
@ -350,6 +356,15 @@ export function applyOptions(
|
|||||||
warn(`Computed property "${key}" has no getter.`)
|
warn(`Computed property "${key}" has no getter.`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (__DEV__) {
|
||||||
|
checkDuplicateProperties!(OptionTypes.COMPUTED, key)
|
||||||
|
if (renderContext[key] && !(key in proxyTarget)) {
|
||||||
|
Object.defineProperty(proxyTarget, key, {
|
||||||
|
enumerable: true,
|
||||||
|
get: () => (renderContext[key] as ComputedRef).value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,8 +372,13 @@ export function applyOptions(
|
|||||||
for (const key in methods) {
|
for (const key in methods) {
|
||||||
const methodHandler = (methods as MethodOptions)[key]
|
const methodHandler = (methods as MethodOptions)[key]
|
||||||
if (isFunction(methodHandler)) {
|
if (isFunction(methodHandler)) {
|
||||||
__DEV__ && checkDuplicateProperties!(OptionTypes.METHODS, key)
|
|
||||||
renderContext[key] = methodHandler.bind(ctx)
|
renderContext[key] = methodHandler.bind(ctx)
|
||||||
|
if (__DEV__) {
|
||||||
|
checkDuplicateProperties!(OptionTypes.METHODS, key)
|
||||||
|
if (!(key in proxyTarget)) {
|
||||||
|
proxyTarget[key] = renderContext[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (__DEV__) {
|
} else if (__DEV__) {
|
||||||
warn(
|
warn(
|
||||||
`Method "${key}" has type "${typeof methodHandler}" in the component definition. ` +
|
`Method "${key}" has type "${typeof methodHandler}" in the component definition. ` +
|
||||||
@ -387,18 +407,24 @@ export function applyOptions(
|
|||||||
if (isArray(injectOptions)) {
|
if (isArray(injectOptions)) {
|
||||||
for (let i = 0; i < injectOptions.length; i++) {
|
for (let i = 0; i < injectOptions.length; i++) {
|
||||||
const key = injectOptions[i]
|
const key = injectOptions[i]
|
||||||
__DEV__ && checkDuplicateProperties!(OptionTypes.INJECT, key)
|
|
||||||
renderContext[key] = inject(key)
|
renderContext[key] = inject(key)
|
||||||
|
if (__DEV__) {
|
||||||
|
checkDuplicateProperties!(OptionTypes.INJECT, key)
|
||||||
|
proxyTarget[key] = renderContext[key]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (const key in injectOptions) {
|
for (const key in injectOptions) {
|
||||||
__DEV__ && checkDuplicateProperties!(OptionTypes.INJECT, key)
|
|
||||||
const opt = injectOptions[key]
|
const opt = injectOptions[key]
|
||||||
if (isObject(opt)) {
|
if (isObject(opt)) {
|
||||||
renderContext[key] = inject(opt.from, opt.default)
|
renderContext[key] = inject(opt.from, opt.default)
|
||||||
} else {
|
} else {
|
||||||
renderContext[key] = inject(opt)
|
renderContext[key] = inject(opt)
|
||||||
}
|
}
|
||||||
|
if (__DEV__) {
|
||||||
|
checkDuplicateProperties!(OptionTypes.INJECT, key)
|
||||||
|
proxyTarget[key] = renderContext[key]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import { ComponentInternalInstance, Data } from './component'
|
|||||||
import { nextTick, queueJob } from './scheduler'
|
import { nextTick, queueJob } from './scheduler'
|
||||||
import { instanceWatch } from './apiWatch'
|
import { instanceWatch } from './apiWatch'
|
||||||
import { EMPTY_OBJ, hasOwn, isGloballyWhitelisted, NOOP } from '@vue/shared'
|
import { EMPTY_OBJ, hasOwn, isGloballyWhitelisted, NOOP } from '@vue/shared'
|
||||||
import { ReactiveEffect, UnwrapRef } from '@vue/reactivity'
|
import { ReactiveEffect, UnwrapRef, toRaw } from '@vue/reactivity'
|
||||||
import {
|
import {
|
||||||
ExtractComputedReturns,
|
ExtractComputedReturns,
|
||||||
ComponentOptionsBase,
|
ComponentOptionsBase,
|
||||||
@ -61,8 +61,8 @@ const publicPropertiesMap: Record<
|
|||||||
$attrs: i => i.attrs,
|
$attrs: i => i.attrs,
|
||||||
$slots: i => i.slots,
|
$slots: i => i.slots,
|
||||||
$refs: i => i.refs,
|
$refs: i => i.refs,
|
||||||
$parent: i => i.parent,
|
$parent: i => i.parent && i.parent.proxy,
|
||||||
$root: i => i.root,
|
$root: i => i.root && i.root.proxy,
|
||||||
$emit: i => i.emit,
|
$emit: i => i.emit,
|
||||||
$options: i => (__FEATURE_OPTIONS__ ? resolveMergedOptions(i) : i.type),
|
$options: i => (__FEATURE_OPTIONS__ ? resolveMergedOptions(i) : i.type),
|
||||||
$forceUpdate: i => () => queueJob(i.update),
|
$forceUpdate: i => () => queueJob(i.update),
|
||||||
@ -77,8 +77,13 @@ const enum AccessTypes {
|
|||||||
OTHER
|
OTHER
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ComponentPublicProxyTarget {
|
||||||
|
[key: string]: any
|
||||||
|
_: ComponentInternalInstance
|
||||||
|
}
|
||||||
|
|
||||||
export const PublicInstanceProxyHandlers: ProxyHandler<any> = {
|
export const PublicInstanceProxyHandlers: ProxyHandler<any> = {
|
||||||
get(target: ComponentInternalInstance, key: string) {
|
get({ _: instance }: ComponentPublicProxyTarget, key: string) {
|
||||||
const {
|
const {
|
||||||
renderContext,
|
renderContext,
|
||||||
data,
|
data,
|
||||||
@ -87,7 +92,7 @@ export const PublicInstanceProxyHandlers: ProxyHandler<any> = {
|
|||||||
type,
|
type,
|
||||||
sink,
|
sink,
|
||||||
appContext
|
appContext
|
||||||
} = target
|
} = instance
|
||||||
|
|
||||||
// data / props / renderContext
|
// data / props / renderContext
|
||||||
// This getter gets called for every property access on the render context
|
// This getter gets called for every property access on the render context
|
||||||
@ -133,7 +138,7 @@ export const PublicInstanceProxyHandlers: ProxyHandler<any> = {
|
|||||||
if (__DEV__ && key === '$attrs') {
|
if (__DEV__ && key === '$attrs') {
|
||||||
markAttrsAccessed()
|
markAttrsAccessed()
|
||||||
}
|
}
|
||||||
return publicGetter(target)
|
return publicGetter(instance)
|
||||||
} else if (hasOwn(sink, key)) {
|
} else if (hasOwn(sink, key)) {
|
||||||
return sink[key]
|
return sink[key]
|
||||||
} else if (
|
} else if (
|
||||||
@ -154,53 +159,131 @@ export const PublicInstanceProxyHandlers: ProxyHandler<any> = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
has(target: ComponentInternalInstance, key: string) {
|
has(
|
||||||
const { data, accessCache, renderContext, type, sink } = target
|
{
|
||||||
|
_: { data, accessCache, renderContext, type, sink }
|
||||||
|
}: ComponentPublicProxyTarget,
|
||||||
|
key: string
|
||||||
|
) {
|
||||||
return (
|
return (
|
||||||
accessCache![key] !== undefined ||
|
accessCache![key] !== undefined ||
|
||||||
(data !== EMPTY_OBJ && hasOwn(data, key)) ||
|
(data !== EMPTY_OBJ && hasOwn(data, key)) ||
|
||||||
hasOwn(renderContext, key) ||
|
hasOwn(renderContext, key) ||
|
||||||
(type.props && hasOwn(type.props, key)) ||
|
(type.props && hasOwn(normalizePropsOptions(type.props)[0], key)) ||
|
||||||
hasOwn(publicPropertiesMap, key) ||
|
hasOwn(publicPropertiesMap, key) ||
|
||||||
hasOwn(sink, key)
|
hasOwn(sink, key)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
set(target: ComponentInternalInstance, key: string, value: any): boolean {
|
set(
|
||||||
const { data, renderContext } = target
|
{ _: instance }: ComponentPublicProxyTarget,
|
||||||
|
key: string,
|
||||||
|
value: any
|
||||||
|
): boolean {
|
||||||
|
const { data, renderContext } = instance
|
||||||
if (data !== EMPTY_OBJ && hasOwn(data, key)) {
|
if (data !== EMPTY_OBJ && hasOwn(data, key)) {
|
||||||
data[key] = value
|
data[key] = value
|
||||||
} else if (hasOwn(renderContext, key)) {
|
} else if (hasOwn(renderContext, key)) {
|
||||||
renderContext[key] = value
|
renderContext[key] = value
|
||||||
} else if (key[0] === '$' && key.slice(1) in target) {
|
} else if (key[0] === '$' && key.slice(1) in instance) {
|
||||||
__DEV__ &&
|
__DEV__ &&
|
||||||
warn(
|
warn(
|
||||||
`Attempting to mutate public property "${key}". ` +
|
`Attempting to mutate public property "${key}". ` +
|
||||||
`Properties starting with $ are reserved and readonly.`,
|
`Properties starting with $ are reserved and readonly.`,
|
||||||
target
|
instance
|
||||||
)
|
)
|
||||||
return false
|
return false
|
||||||
} else if (key in target.props) {
|
} else if (key in instance.props) {
|
||||||
__DEV__ &&
|
__DEV__ &&
|
||||||
warn(`Attempting to mutate prop "${key}". Props are readonly.`, target)
|
warn(
|
||||||
|
`Attempting to mutate prop "${key}". Props are readonly.`,
|
||||||
|
instance
|
||||||
|
)
|
||||||
return false
|
return false
|
||||||
} else {
|
} else {
|
||||||
target.sink[key] = value
|
instance.sink[key] = value
|
||||||
|
if (__DEV__) {
|
||||||
|
instance.proxyTarget[key] = value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const runtimeCompiledRenderProxyHandlers = {
|
export const RuntimeCompiledPublicInstanceProxyHandlers = {
|
||||||
...PublicInstanceProxyHandlers,
|
...PublicInstanceProxyHandlers,
|
||||||
get(target: ComponentInternalInstance, key: string) {
|
get(target: ComponentPublicProxyTarget, key: string) {
|
||||||
// fast path for unscopables when using `with` block
|
// fast path for unscopables when using `with` block
|
||||||
if ((key as any) === Symbol.unscopables) {
|
if ((key as any) === Symbol.unscopables) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return PublicInstanceProxyHandlers.get!(target, key, target)
|
return PublicInstanceProxyHandlers.get!(target, key, target)
|
||||||
},
|
},
|
||||||
has(_target: ComponentInternalInstance, key: string) {
|
has(_: ComponentPublicProxyTarget, key: string) {
|
||||||
return key[0] !== '_' && !isGloballyWhitelisted(key)
|
return key[0] !== '_' && !isGloballyWhitelisted(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In dev mode, the proxy target exposes the same properties as seen on `this`
|
||||||
|
// for easier console inspection. In prod mode it will be an empty object so
|
||||||
|
// these properties definitions can be skipped.
|
||||||
|
export function createDevProxyTarget(instance: ComponentInternalInstance) {
|
||||||
|
const target: Record<string, any> = {}
|
||||||
|
|
||||||
|
// expose internal instance for proxy handlers
|
||||||
|
Object.defineProperty(target, `_`, {
|
||||||
|
get: () => instance
|
||||||
|
})
|
||||||
|
|
||||||
|
// expose public properties
|
||||||
|
Object.keys(publicPropertiesMap).forEach(key => {
|
||||||
|
Object.defineProperty(target, key, {
|
||||||
|
get: () => publicPropertiesMap[key](instance)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// expose global properties
|
||||||
|
const { globalProperties } = instance.appContext.config
|
||||||
|
Object.keys(globalProperties).forEach(key => {
|
||||||
|
Object.defineProperty(target, key, {
|
||||||
|
get: () => globalProperties[key]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return target as ComponentPublicProxyTarget
|
||||||
|
}
|
||||||
|
|
||||||
|
export function exposePropsOnDevProxyTarget(
|
||||||
|
instance: ComponentInternalInstance
|
||||||
|
) {
|
||||||
|
const {
|
||||||
|
proxyTarget,
|
||||||
|
type: { props: propsOptions }
|
||||||
|
} = instance
|
||||||
|
if (propsOptions) {
|
||||||
|
Object.keys(normalizePropsOptions(propsOptions)[0]).forEach(key => {
|
||||||
|
Object.defineProperty(proxyTarget, key, {
|
||||||
|
enumerable: true,
|
||||||
|
get: () => instance.props[key],
|
||||||
|
// intercepted by the proxy so no need for implementation,
|
||||||
|
// but needed to prevent set errors
|
||||||
|
set: NOOP
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function exposeRenderContextOnDevProxyTarget(
|
||||||
|
instance: ComponentInternalInstance
|
||||||
|
) {
|
||||||
|
const { proxyTarget, renderContext } = instance
|
||||||
|
Object.keys(toRaw(renderContext)).forEach(key => {
|
||||||
|
Object.defineProperty(proxyTarget, key, {
|
||||||
|
enumerable: true,
|
||||||
|
get: () => renderContext[key],
|
||||||
|
// intercepted by the proxy so no need for implementation,
|
||||||
|
// but needed to prevent set errors
|
||||||
|
set: NOOP
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -419,7 +419,7 @@ function createSuspenseBoundary(
|
|||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
pushWarningContext(vnode)
|
pushWarningContext(vnode)
|
||||||
}
|
}
|
||||||
handleSetupResult(instance, asyncSetupResult, suspense, false)
|
handleSetupResult(instance, asyncSetupResult, false)
|
||||||
if (hydratedEl) {
|
if (hydratedEl) {
|
||||||
// vnode may have been replaced if an update happened before the
|
// vnode may have been replaced if an update happened before the
|
||||||
// async dep is reoslved.
|
// async dep is reoslved.
|
||||||
|
Loading…
Reference in New Issue
Block a user