]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
refactor: use flat options on class
authorEvan You <yyx990803@gmail.com>
Wed, 10 Oct 2018 00:22:29 +0000 (20:22 -0400)
committerEvan You <yyx990803@gmail.com>
Wed, 10 Oct 2018 00:22:29 +0000 (20:22 -0400)
packages/core/__tests__/attrsFallthrough.spec.ts
packages/core/src/component.ts
packages/core/src/componentComputed.ts
packages/core/src/componentOptions.ts
packages/core/src/componentProps.ts
packages/core/src/componentProxy.ts
packages/core/src/componentUtils.ts
packages/core/src/optional/context.ts
packages/core/src/optional/keepAlive.ts

index a6df61ceb55a72dc092345076e8ee3f40d2751b5..7d59e19eb4b0ad54db19f23a5330b51fed6865d0 100644 (file)
@@ -95,10 +95,8 @@ describe('attribute fallthrough', () => {
     }
 
     class Child extends Component<{ foo: number }> {
-      static options = {
-        props: {
-          foo: Number
-        }
+      static props = {
+        foo: Number
       }
       updated() {
         childUpdated()
@@ -169,10 +167,8 @@ describe('attribute fallthrough', () => {
     }
 
     class Child extends Component {
-      static options = {
-        props: {
-          foo: Number
-        }
+      static props = {
+        foo: Number
       }
       updated() {
         childUpdated()
@@ -183,10 +179,8 @@ describe('attribute fallthrough', () => {
     }
 
     class GrandChild extends Component<{ foo: number }> {
-      static options = {
-        props: {
-          foo: Number
-        }
+      static props = {
+        foo: Number
       }
       updated() {
         grandChildUpdated()
index 5099b39675287a6884a242ec75dea3b4609b800b..9f01c284b8e0592cad37ef5d415b853a3bf7973a 100644 (file)
@@ -3,6 +3,7 @@ import { VNode, Slots, RenderNode, MountedVNode } from './vdom'
 import {
   Data,
   ComponentOptions,
+  ComponentClassOptions,
   ComponentPropsOptions,
   WatchOptions
 } from './componentOptions'
@@ -10,10 +11,10 @@ import { setupWatcher } from './componentWatch'
 import { Autorun, DebuggerEvent, ComputedGetter } from '@vue/observer'
 import { nextTick } from '@vue/scheduler'
 import { ErrorTypes } from './errorHandling'
+import { resolveComponentOptions } from './componentUtils'
 
-type Flatten<T> = { [K in keyof T]: T[K] }
-
-export interface ComponentClass extends Flatten<typeof InternalComponent> {
+export interface ComponentClass extends ComponentClassOptions {
+  options?: ComponentOptions
   new <P extends object = {}, D extends object = {}>(): MergedComponent<P, D>
 }
 
@@ -30,15 +31,15 @@ export interface FunctionalComponent<P = {}> {
 export type ComponentType = ComponentClass | FunctionalComponent
 
 export interface ComponentInstance<P = {}, D = {}> extends InternalComponent {
+  constructor: ComponentClass
+
   $vnode: MountedVNode
   $data: D
   $props: Readonly<P>
   $attrs: Data
-  $computed: Data
   $slots: Slots
   $root: ComponentInstance
   $children: ComponentInstance[]
-  $options: ComponentOptions<this>
 
   data?(): Partial<D>
   render(props: Readonly<P>, slots: Slots, attrs: Data): any
@@ -70,8 +71,6 @@ export interface ComponentInstance<P = {}, D = {}> extends InternalComponent {
 }
 
 class InternalComponent {
-  public static options?: ComponentOptions
-
   public get $el(): RenderNode | null {
     return this.$vnode && this.$vnode.el
   }
@@ -81,12 +80,11 @@ class InternalComponent {
   public $data: Data | null = null
   public $props: Data | null = null
   public $attrs: Data | null = null
-  public $computed: Data | null = null
   public $slots: Slots | null = null
   public $root: ComponentInstance | null = null
   public $parent: ComponentInstance | null = null
   public $children: ComponentInstance[] = []
-  public $options: any
+  public $options: ComponentOptions
   public $refs: Record<string, ComponentInstance | RenderNode> = {}
   public $proxy: any = null
   public $forceUpdate: (() => void) | null = null
@@ -103,12 +101,10 @@ class InternalComponent {
   public _isVue: boolean = true
   public _inactiveRoot: boolean = false
 
-  constructor(options?: ComponentOptions) {
-    this.$options = options || (this.constructor as any).options || EMPTY_OBJ
-    // root instance
-    if (options !== void 0) {
-      // mount this
-    }
+  constructor() {
+    this.$options =
+      (this.constructor as ComponentClass).options ||
+      resolveComponentOptions(this.constructor as ComponentClass)
   }
 
   $nextTick(fn: () => any): Promise<any> {
index 19fd0ad0dd4d0a978c15333ff76b521ebf8bd705..fa44269530e443e0850d02cd428c9d025410f2a8 100644 (file)
@@ -1,21 +1,12 @@
-import { EMPTY_OBJ, NOOP } from './utils'
+import { NOOP } from './utils'
 import { computed, stop, ComputedGetter } from '@vue/observer'
 import { ComponentClass, ComponentInstance } from './component'
 import { ComponentComputedOptions } from './componentOptions'
 
-const extractionCache: WeakMap<
-  ComponentClass,
-  ComponentComputedOptions
-> = new WeakMap()
-
-export function getComputedOptions(
+export function resolveComputedOptions(
   comp: ComponentClass
 ): ComponentComputedOptions {
-  let computedOptions = extractionCache.get(comp)
-  if (computedOptions) {
-    return computedOptions
-  }
-  computedOptions = {}
+  const computedOptions: ComponentComputedOptions = {}
   const descriptors = Object.getOwnPropertyDescriptors(comp.prototype as any)
   for (const key in descriptors) {
     const d = descriptors[key]
@@ -25,7 +16,6 @@ export function getComputedOptions(
       // as it's already defined on the prototype
     }
   }
-  extractionCache.set(comp, computedOptions)
   return computedOptions
 }
 
@@ -34,7 +24,6 @@ export function initializeComputed(
   computedOptions: ComponentComputedOptions | undefined
 ) {
   if (!computedOptions) {
-    instance.$computed = EMPTY_OBJ
     return
   }
   const handles: Record<
@@ -47,17 +36,6 @@ export function initializeComputed(
     const getter = typeof option === 'function' ? option : option.get || NOOP
     handles[key] = computed(getter, proxy)
   }
-  instance.$computed = new Proxy(
-    {},
-    {
-      get(_, key: any) {
-        if (handles.hasOwnProperty(key)) {
-          return handles[key]()
-        }
-      }
-      // TODO should be readonly
-    }
-  )
 }
 
 export function teardownComputed(instance: ComponentInstance) {
index 60bd1cb306c22740990344b093bf727a92ac3ebe..a75148bad8bbc14a55621d1c78b437647076d168 100644 (file)
@@ -3,14 +3,18 @@ import { Slots } from './vdom'
 
 export type Data = Record<string, any>
 
-export interface ComponentOptions<This = ComponentInstance> {
-  data?(): object
+export interface ComponentClassOptions<This = ComponentInstance> {
   props?: ComponentPropsOptions
   computed?: ComponentComputedOptions<This>
   watch?: ComponentWatchOptions<This>
-  render?: (this: This, props: Readonly<Data>, slots: Slots, attrs: Data) => any
-  inheritAttrs?: boolean
   displayName?: string
+  inheritAttrs?: boolean
+}
+
+export interface ComponentOptions<This = ComponentInstance>
+  extends ComponentClassOptions<This> {
+  data?(): object
+  render?: (this: This, props: Readonly<Data>, slots: Slots, attrs: Data) => any
   // TODO other options
   readonly [key: string]: any
 }
index 17c42526173f3ece9c6b4a1891fc24b0d0851e52..fe95aa8184499696500d10dbe1f919b2444c906a 100644 (file)
@@ -18,9 +18,10 @@ import {
 
 export function initializeProps(
   instance: ComponentInstance,
+  options: ComponentPropsOptions | undefined,
   data: Data | null
 ) {
-  const { props, attrs } = resolveProps(data, instance.$options.props)
+  const { props, attrs } = resolveProps(data, options)
   instance.$props = immutable(props || {})
   instance.$attrs = immutable(attrs || {})
 }
@@ -32,7 +33,7 @@ export function updateProps(instance: ComponentInstance, nextData: Data) {
   if (nextData != null) {
     const { props: nextProps, attrs: nextAttrs } = resolveProps(
       nextData,
-      instance.$options.props
+      instance.constructor.props
     )
     // unlock to temporarily allow mutatiing props
     unlock()
index 33dc6ff5aff33c46c441565089893d7127ca498c..43bfd7251c380b6934604d712b1c82c8da22da48 100644 (file)
@@ -25,8 +25,8 @@ const renderProxyHandlers = {
       // data
       return target.$data[key]
     } else if (
-      target.$options.props != null &&
-      target.$options.props.hasOwnProperty(key)
+      target.constructor.props != null &&
+      target.constructor.props.hasOwnProperty(key)
     ) {
       // props are only proxied if declared
       return target.$props[key]
@@ -61,8 +61,8 @@ const renderProxyHandlers = {
         return false
       }
       if (
-        target.$options.props != null &&
-        target.$options.props.hasOwnProperty(key)
+        target.constructor.props != null &&
+        target.constructor.props.hasOwnProperty(key)
       ) {
         // TODO warn props are immutable
         return false
index 740c4e2c6a1f600e28464fbec1ca114cea39c7fb..04d8705ceec1fccc1ae17530822f863b53707992 100644 (file)
@@ -8,7 +8,7 @@ import { initializeState } from './componentState'
 import { initializeProps } from './componentProps'
 import {
   initializeComputed,
-  getComputedOptions,
+  resolveComputedOptions,
   teardownComputed
 } from './componentComputed'
 import { initializeWatch, teardownWatch } from './componentWatch'
@@ -40,11 +40,10 @@ export function createComponentInstance(
   if (instance.beforeCreate) {
     instance.beforeCreate.call(proxy)
   }
-  // TODO provide/inject
-  initializeProps(instance, vnode.data)
+  initializeProps(instance, Component.props, vnode.data)
   initializeState(instance)
-  initializeComputed(instance, getComputedOptions(Component))
-  initializeWatch(instance, instance.$options.watch)
+  initializeComputed(instance, Component.computed)
+  initializeWatch(instance, Component.watch)
   instance.$slots = vnode.slots || EMPTY_OBJ
   if (instance.created) {
     instance.created.call(proxy)
@@ -75,7 +74,7 @@ export function renderInstanceRoot(instance: ComponentInstance): VNode {
     vnode,
     instance.$parentVNode,
     instance.$attrs,
-    instance.$options.inheritAttrs
+    instance.constructor.inheritAttrs
   )
 }
 
@@ -171,36 +170,40 @@ export function createComponentClassFromOptions(
   options: ComponentOptions
 ): ComponentClass {
   class AnonymousComponent extends Component {
-    constructor() {
-      super()
-      this.$options = options
-    }
+    static options = options
   }
   const proto = AnonymousComponent.prototype as any
   for (const key in options) {
     const value = options[key]
     // name -> displayName
-    if (__COMPAT__ && key === 'name') {
-      options.displayName = options.name
-    }
-    if (typeof value === 'function') {
-      if (__COMPAT__ && key === 'render') {
-        proto[key] = function() {
-          return value.call(this, h)
+    if (key === 'name') {
+      AnonymousComponent.displayName = options.name
+    } else if (typeof value === 'function') {
+      if (__COMPAT__) {
+        if (key === 'render') {
+          proto[key] = function() {
+            return value.call(this, h)
+          }
+        } else if (key === 'beforeDestroy') {
+          proto.beforeUnmount = value
+        } else if (key === 'destroyed') {
+          proto.unmounted = value
         }
       } else {
         proto[key] = value
       }
-    }
-    if (key === 'computed') {
-      const isGet = typeof value === 'function'
-      Object.defineProperty(proto, key, {
-        configurable: true,
-        get: isGet ? value : value.get,
-        set: isGet ? undefined : value.set
-      })
-    }
-    if (key === 'methods') {
+    } else if (key === 'computed') {
+      AnonymousComponent.computed = value
+      for (const computedKey in value) {
+        const computed = value[computedKey]
+        const isGet = typeof computed === 'function'
+        Object.defineProperty(proto, computedKey, {
+          configurable: true,
+          get: isGet ? computed : computed.get,
+          set: isGet ? undefined : computed.set
+        })
+      }
+    } else if (key === 'methods') {
       for (const method in value) {
         if (__DEV__ && proto.hasOwnProperty(method)) {
           console.warn(
@@ -210,7 +213,23 @@ export function createComponentClassFromOptions(
         }
         proto[method] = value[method]
       }
+    } else {
+      ;(AnonymousComponent as any)[key] = value
     }
   }
   return AnonymousComponent as ComponentClass
 }
+
+export function resolveComponentOptions(
+  Component: ComponentClass
+): ComponentOptions {
+  const keys = Object.keys(Component)
+  const options = {} as any
+  for (let i = 0; i < keys.length; i++) {
+    const key = keys[i]
+    options[key] = (Component as any)[key]
+  }
+  Component.computed = options.computed = resolveComputedOptions(Component)
+  Component.options = options
+  return options
+}
index a260370db8dda65b743dbd8d835086651cebe079..595972f4537f343fedb6e2985ff70f03eab6b3c9 100644 (file)
@@ -9,6 +9,16 @@ interface ProviderProps {
 }
 
 export class Provide extends Component<ProviderProps> {
+  static props = {
+    id: {
+      type: [String, Symbol],
+      required: true
+    },
+    value: {
+      required: true
+    }
+  }
+
   updateValue() {
     // TS doesn't allow symbol as index :/
     // https://github.com/Microsoft/TypeScript/issues/24587
@@ -43,18 +53,6 @@ export class Provide extends Component<ProviderProps> {
   }
 }
 
-Provide.options = {
-  props: {
-    id: {
-      type: [String, Symbol],
-      required: true
-    },
-    value: {
-      required: true
-    }
-  }
-}
-
 export class Inject extends Component {
   render(props: any, slots: any) {
     return slots.default && slots.default(contextStore[props.id])
index 17d6a19866baebe1f6c3719912f39d23969ce0ac..ec95e6552e5cc11db8ff9f596d50371c8bf2c4c2 100644 (file)
@@ -114,7 +114,7 @@ export class KeepAlive extends Component<KeepAliveProps> {
 ;(KeepAlive as any)[KeepAliveSymbol] = true
 
 function getName(comp: ComponentClass): string | void {
-  return comp.options && comp.options.name
+  return comp.displayName || comp.name
 }
 
 function matches(pattern: MatchPattern, name: string): boolean {