From 24e5ab33f530888b82cc25fbf051d7abc052323b Mon Sep 17 00:00:00 2001 From: Evan You Date: Thu, 16 Apr 2020 10:09:13 -0400 Subject: [PATCH] refactor(runtime-core): remove need for internal instance sink --- .../__tests__/componentProxy.spec.ts | 10 ++++---- packages/runtime-core/src/component.ts | 12 ++++------ packages/runtime-core/src/componentProxy.ts | 22 +++++++++++------- .../runtime-core/src/components/KeepAlive.ts | 23 +++++++++---------- packages/runtime-core/src/renderer.ts | 10 ++++---- 5 files changed, 39 insertions(+), 38 deletions(-) diff --git a/packages/runtime-core/__tests__/componentProxy.spec.ts b/packages/runtime-core/__tests__/componentProxy.spec.ts index 753dbac4b..cd03ce702 100644 --- a/packages/runtime-core/__tests__/componentProxy.spec.ts +++ b/packages/runtime-core/__tests__/componentProxy.spec.ts @@ -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) diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index 9bbcc8567..da31dfdaa 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -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 | 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, diff --git a/packages/runtime-core/src/componentProxy.ts b/packages/runtime-core/src/componentProxy.ts index 74c5c5912..13954b40b 100644 --- a/packages/runtime-core/src/componentProxy.ts +++ b/packages/runtime-core/src/componentProxy.ts @@ -95,7 +95,7 @@ export const PublicInstanceProxyHandlers: ProxyHandler = { props, accessCache, type, - sink, + proxyTarget, appContext } = instance @@ -136,7 +136,8 @@ export const PublicInstanceProxyHandlers: ProxyHandler = { } } - // 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 = { 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 = { ) 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 = { has( { - _: { data, accessCache, renderContext, type, sink, appContext } + _: { data, accessCache, renderContext, type, proxyTarget, appContext } }: ComponentPublicProxyTarget, key: string ) { @@ -210,7 +216,7 @@ export const PublicInstanceProxyHandlers: ProxyHandler = { 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) ) } diff --git a/packages/runtime-core/src/components/KeepAlive.ts b/packages/runtime-core/src/components/KeepAlive.ts index ff53876c3..50a4f7567 100644 --- a/packages/runtime-core/src/components/KeepAlive.ts +++ b/packages/runtime-core/src/components/KeepAlive.ts @@ -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 type Keys = Set -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! diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index ab854b11f..39fbb3f11 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -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) }