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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user