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()
})
test('sink', async () => {
test('user attached properties', async () => {
let instance: ComponentInternalInstance
let instanceProxy: any
const Comp = {
@ -116,7 +116,7 @@ describe('component: proxy', () => {
render(h(Comp), nodeOps.createElement('div'))
instanceProxy.foo = 1
expect(instanceProxy.foo).toBe(1)
expect(instance!.sink.foo).toBe(1)
expect(instance!.proxyTarget.foo).toBe(1)
})
test('globalProperties', () => {
@ -140,8 +140,8 @@ describe('component: proxy', () => {
// set should overwrite globalProperties with local
instanceProxy.foo = 2
expect(instanceProxy.foo).toBe(2)
expect(instance!.sink.foo).toBe(2)
// expect(instanceProxy.foo).toBe(2)
expect(instance!.proxyTarget.foo).toBe(2)
// should not affect global
expect(app.config.globalProperties.foo).toBe(1)
})
@ -188,7 +188,7 @@ describe('component: proxy', () => {
expect('$foobar' 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
expect('baz' in instanceProxy).toBe(true)

View File

@ -143,6 +143,11 @@ export interface ComponentInternalInstance {
attrs: Data
slots: InternalSlots
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
// alternative proxy used only for runtime-compiled render functions using
// `with` block
@ -156,9 +161,6 @@ export interface ComponentInternalInstance {
asyncDep: Promise<any> | null
asyncResolved: boolean
// storage for any extra properties
sink: { [key: string]: any }
// lifecycle
isMounted: boolean
isUnmounted: boolean
@ -230,10 +232,6 @@ export function createComponentInstance(
asyncDep: null,
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
// not using enums here because it results in computed properties
isMounted: false,

View File

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

View File

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

View File

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