refactor(runtime-core): remove need for internal instance sink

This commit is contained in:
Evan You 2020-04-16 10:09:13 -04:00
parent 4d014dc3d3
commit 24e5ab33f5
5 changed files with 39 additions and 38 deletions

View File

@ -101,7 +101,7 @@ describe('component: proxy', () => {
expect(`Attempting to mutate public property "$data"`).toHaveBeenWarned() expect(`Attempting to mutate public property "$data"`).toHaveBeenWarned()
}) })
test('sink', async () => { test('user attached properties', async () => {
let instance: ComponentInternalInstance let instance: ComponentInternalInstance
let instanceProxy: any let instanceProxy: any
const Comp = { const Comp = {
@ -116,7 +116,7 @@ describe('component: proxy', () => {
render(h(Comp), nodeOps.createElement('div')) render(h(Comp), nodeOps.createElement('div'))
instanceProxy.foo = 1 instanceProxy.foo = 1
expect(instanceProxy.foo).toBe(1) expect(instanceProxy.foo).toBe(1)
expect(instance!.sink.foo).toBe(1) expect(instance!.proxyTarget.foo).toBe(1)
}) })
test('globalProperties', () => { test('globalProperties', () => {
@ -140,8 +140,8 @@ describe('component: proxy', () => {
// set should overwrite globalProperties with local // set should overwrite globalProperties with local
instanceProxy.foo = 2 instanceProxy.foo = 2
expect(instanceProxy.foo).toBe(2) // expect(instanceProxy.foo).toBe(2)
expect(instance!.sink.foo).toBe(2) expect(instance!.proxyTarget.foo).toBe(2)
// should not affect global // should not affect global
expect(app.config.globalProperties.foo).toBe(1) expect(app.config.globalProperties.foo).toBe(1)
}) })
@ -188,7 +188,7 @@ describe('component: proxy', () => {
expect('$foobar' in instanceProxy).toBe(false) expect('$foobar' in instanceProxy).toBe(false)
expect('baz' in instanceProxy).toBe(false) expect('baz' in instanceProxy).toBe(false)
// set non-existent (goes into sink) // set non-existent (goes into proxyTarget sink)
instanceProxy.baz = 1 instanceProxy.baz = 1
expect('baz' in instanceProxy).toBe(true) expect('baz' in instanceProxy).toBe(true)

View File

@ -143,6 +143,11 @@ export interface ComponentInternalInstance {
attrs: Data attrs: Data
slots: InternalSlots slots: InternalSlots
proxy: ComponentPublicInstance | null proxy: ComponentPublicInstance | null
// The target object for the public instance proxy. In dev mode, we also
// define getters for all known instance properties on it so it can be
// properly inspected in the console. These getters are skipped in prod mode
// for performance. In addition, any user attached properties
// (via `this.x = ...`) are also stored on this object.
proxyTarget: ComponentPublicProxyTarget 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
@ -156,9 +161,6 @@ export interface ComponentInternalInstance {
asyncDep: Promise<any> | null asyncDep: Promise<any> | null
asyncResolved: boolean asyncResolved: boolean
// storage for any extra properties
sink: { [key: string]: any }
// lifecycle // lifecycle
isMounted: boolean isMounted: boolean
isUnmounted: boolean isUnmounted: boolean
@ -230,10 +232,6 @@ export function createComponentInstance(
asyncDep: null, asyncDep: null,
asyncResolved: false, asyncResolved: false,
// user namespace for storing whatever the user assigns to `this`
// can also be used as a wildcard storage for ad-hoc injections internally
sink: {},
// lifecycle hooks // lifecycle hooks
// not using enums here because it results in computed properties // not using enums here because it results in computed properties
isMounted: false, isMounted: false,

View File

@ -95,7 +95,7 @@ export const PublicInstanceProxyHandlers: ProxyHandler<any> = {
props, props,
accessCache, accessCache,
type, type,
sink, proxyTarget,
appContext appContext
} = instance } = instance
@ -136,7 +136,8 @@ export const PublicInstanceProxyHandlers: ProxyHandler<any> = {
} }
} }
// public $xxx properties & user-attached properties (sink) // public $xxx properties &
// user-attached properties (falls through to proxyTarget)
const publicGetter = publicPropertiesMap[key] const publicGetter = publicPropertiesMap[key]
let cssModule, globalProperties let cssModule, globalProperties
if (publicGetter) { if (publicGetter) {
@ -144,8 +145,8 @@ export const PublicInstanceProxyHandlers: ProxyHandler<any> = {
markAttrsAccessed() markAttrsAccessed()
} }
return publicGetter(instance) return publicGetter(instance)
} else if (hasOwn(sink, key)) { } else if (hasOwn(proxyTarget, key)) {
return sink[key] return proxyTarget[key]
} else if ( } else if (
(cssModule = type.__cssModules) && (cssModule = type.__cssModules) &&
(cssModule = cssModule[key]) (cssModule = cssModule[key])
@ -190,8 +191,13 @@ export const PublicInstanceProxyHandlers: ProxyHandler<any> = {
) )
return false return false
} else { } else {
instance.sink[key] = value if (__DEV__ && key in instance.appContext.config.globalProperties) {
if (__DEV__) { Object.defineProperty(instance.proxyTarget, key, {
configurable: true,
enumerable: true,
value
})
} else {
instance.proxyTarget[key] = value instance.proxyTarget[key] = value
} }
} }
@ -200,7 +206,7 @@ export const PublicInstanceProxyHandlers: ProxyHandler<any> = {
has( has(
{ {
_: { data, accessCache, renderContext, type, sink, appContext } _: { data, accessCache, renderContext, type, proxyTarget, appContext }
}: ComponentPublicProxyTarget, }: ComponentPublicProxyTarget,
key: string key: string
) { ) {
@ -210,7 +216,7 @@ export const PublicInstanceProxyHandlers: ProxyHandler<any> = {
hasOwn(renderContext, key) || hasOwn(renderContext, key) ||
(type.props && hasOwn(normalizePropsOptions(type.props)[0]!, key)) || (type.props && hasOwn(normalizePropsOptions(type.props)[0]!, key)) ||
hasOwn(publicPropertiesMap, key) || hasOwn(publicPropertiesMap, key) ||
hasOwn(sink, key) || hasOwn(proxyTarget, key) ||
hasOwn(appContext.config.globalProperties, key) hasOwn(appContext.config.globalProperties, key)
) )
} }

View File

@ -18,7 +18,6 @@ import {
invokeArrayFns invokeArrayFns
} from '@vue/shared' } from '@vue/shared'
import { watch } from '../apiWatch' import { watch } from '../apiWatch'
import { SuspenseBoundary } from './Suspense'
import { import {
RendererInternals, RendererInternals,
queuePostRenderEffect, queuePostRenderEffect,
@ -27,6 +26,7 @@ import {
RendererNode RendererNode
} from '../renderer' } from '../renderer'
import { setTransitionHooks } from './BaseTransition' import { setTransitionHooks } from './BaseTransition'
import { ComponentPublicProxyTarget } from '../componentProxy'
type MatchPattern = string | RegExp | string[] | RegExp[] type MatchPattern = string | RegExp | string[] | RegExp[]
@ -40,9 +40,8 @@ type CacheKey = string | number | Component
type Cache = Map<CacheKey, VNode> type Cache = Map<CacheKey, VNode>
type Keys = Set<CacheKey> type Keys = Set<CacheKey>
export interface KeepAliveSink { export interface KeepAliveContext extends ComponentPublicProxyTarget {
renderer: RendererInternals renderer: RendererInternals
parentSuspense: SuspenseBoundary | null
activate: ( activate: (
vnode: VNode, vnode: VNode,
container: RendererElement, container: RendererElement,
@ -76,25 +75,25 @@ const KeepAliveImpl = {
let current: VNode | null = null let current: VNode | null = null
const instance = getCurrentInstance()! const instance = getCurrentInstance()!
const parentSuspense = instance.suspense
// KeepAlive communicates with the instantiated renderer via the "sink" // KeepAlive communicates with the instantiated renderer via the proxyTarget
// where the renderer passes in platform-specific functions, and the // as a shared context where the renderer passes in its internals,
// KeepAlive instance exposes activate/deactivate implementations. // and the KeepAlive instance exposes activate/deactivate implementations.
// The whole point of this is to avoid importing KeepAlive directly in the // The whole point of this is to avoid importing KeepAlive directly in the
// renderer to facilitate tree-shaking. // renderer to facilitate tree-shaking.
const sink = instance.sink as KeepAliveSink const sharedContext = instance.proxyTarget as KeepAliveContext
const { const {
renderer: { renderer: {
p: patch, p: patch,
m: move, m: move,
um: _unmount, um: _unmount,
o: { createElement } o: { createElement }
}, }
parentSuspense } = sharedContext
} = sink
const storageContainer = createElement('div') const storageContainer = createElement('div')
sink.activate = (vnode, container, anchor, isSVG, optimized) => { sharedContext.activate = (vnode, container, anchor, isSVG, optimized) => {
const child = vnode.component! const child = vnode.component!
move(vnode, container, anchor, MoveType.ENTER, parentSuspense) move(vnode, container, anchor, MoveType.ENTER, parentSuspense)
// in case props have changed // in case props have changed
@ -116,7 +115,7 @@ const KeepAliveImpl = {
}, parentSuspense) }, parentSuspense)
} }
sink.deactivate = (vnode: VNode) => { sharedContext.deactivate = (vnode: VNode) => {
move(vnode, storageContainer, null, MoveType.LEAVE, parentSuspense) move(vnode, storageContainer, null, MoveType.LEAVE, parentSuspense)
queuePostRenderEffect(() => { queuePostRenderEffect(() => {
const component = vnode.component! const component = vnode.component!

View File

@ -53,7 +53,7 @@ import {
SuspenseImpl SuspenseImpl
} from './components/Suspense' } from './components/Suspense'
import { TeleportImpl } from './components/Teleport' import { TeleportImpl } from './components/Teleport'
import { KeepAliveSink, isKeepAlive } from './components/KeepAlive' import { isKeepAlive, KeepAliveContext } from './components/KeepAlive'
import { registerHMR, unregisterHMR } from './hmr' import { registerHMR, unregisterHMR } from './hmr'
import { import {
ErrorCodes, ErrorCodes,
@ -949,7 +949,7 @@ function baseCreateRenderer(
) => { ) => {
if (n1 == null) { if (n1 == null) {
if (n2.shapeFlag & ShapeFlags.COMPONENT_KEPT_ALIVE) { if (n2.shapeFlag & ShapeFlags.COMPONENT_KEPT_ALIVE) {
;(parentComponent!.sink as KeepAliveSink).activate( ;(parentComponent!.proxyTarget as KeepAliveContext).activate(
n2, n2,
container, container,
anchor, anchor,
@ -998,9 +998,7 @@ function baseCreateRenderer(
// inject renderer internals for keepAlive // inject renderer internals for keepAlive
if (isKeepAlive(initialVNode)) { if (isKeepAlive(initialVNode)) {
const sink = instance.sink as KeepAliveSink ;(instance.proxyTarget as KeepAliveContext).renderer = internals
sink.renderer = internals
sink.parentSuspense = parentSuspense
} }
// resolve props and slots for setup context // resolve props and slots for setup context
@ -1721,7 +1719,7 @@ function baseCreateRenderer(
if (shapeFlag & ShapeFlags.COMPONENT) { if (shapeFlag & ShapeFlags.COMPONENT) {
if (shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE) { if (shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE) {
;(parentComponent!.sink as KeepAliveSink).deactivate(vnode) ;(parentComponent!.proxyTarget as KeepAliveContext).deactivate(vnode)
} else { } else {
unmountComponent(vnode.component!, parentSuspense, doRemove) unmountComponent(vnode.component!, parentSuspense, doRemove)
} }