]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
wip: optimize w/ shapeFlag
authorEvan You <yyx990803@gmail.com>
Sun, 2 Jun 2019 08:35:19 +0000 (16:35 +0800)
committerEvan You <yyx990803@gmail.com>
Sun, 2 Jun 2019 08:35:19 +0000 (16:35 +0800)
packages/observer/src/effect.ts
packages/runtime-core/src/component.ts
packages/runtime-core/src/createRenderer.ts
packages/runtime-core/src/shapeFlags.ts [new file with mode: 0644]
packages/runtime-core/src/vnode.ts

index ea136aed5c1a562aa7b50d34b9939116761610e6..e7438f526047bea5ab8900415f298f9bb4e1afef 100644 (file)
@@ -70,10 +70,13 @@ function run(effect: ReactiveEffect, fn: Function, args: any[]): any {
 }
 
 export function cleanup(effect: ReactiveEffect) {
-  for (let i = 0; i < effect.deps.length; i++) {
-    effect.deps[i].delete(effect)
+  const { deps } = effect
+  if (deps.length) {
+    for (let i = 0; i < deps.length; i++) {
+      deps[i].delete(effect)
+    }
+    deps.length = 0
   }
-  effect.deps.length = 0
 }
 
 export function track(
index d34500818096378f0e66e008b499078a36017076..4a36227c43eaf59c3630019fcba4e57f47db0eaf 100644 (file)
@@ -5,11 +5,12 @@ import {
   observable,
   immutable
 } from '@vue/observer'
-import { isFunction, EMPTY_OBJ } from '@vue/shared'
+import { EMPTY_OBJ } from '@vue/shared'
 import { RenderProxyHandlers } from './componentProxy'
 import { ComponentPropsOptions, ExtractPropTypes } from './componentProps'
 import { PROPS, DYNAMIC_SLOTS, FULL_PROPS } from './patchFlags'
 import { Slots } from './componentSlots'
+import { STATEFUL_COMPONENT } from './shapeFlags'
 
 export type Data = { [key: string]: any }
 
@@ -148,16 +149,17 @@ export function setupStatefulComponent(instance: ComponentInstance) {
 }
 
 export function renderComponentRoot(instance: ComponentInstance): VNode {
-  const { type: Component, renderProxy } = instance
-  if (isFunction(Component)) {
-    return normalizeVNode(Component(instance))
-  } else {
-    if (__DEV__ && !Component.render) {
+  const { type: Component, vnode } = instance
+  if (vnode.shapeFlag & STATEFUL_COMPONENT) {
+    if (__DEV__ && !(Component as any).render) {
       // TODO warn missing render
     }
     return normalizeVNode(
-      (Component.render as Function).call(renderProxy, instance)
+      (Component as any).render.call(instance.renderProxy, instance)
     )
+  } else {
+    // functional
+    return normalizeVNode((Component as FunctionalComponent)(instance))
   }
 }
 
index de0a3d8e53728855ee6724fcd432821b5aee35fa..186dfb77a67b9fe32d0b51afa68586d05effc92b 100644 (file)
@@ -14,14 +14,7 @@ import {
   createComponentInstance,
   setupStatefulComponent
 } from './component'
-import {
-  isString,
-  isArray,
-  isFunction,
-  isObject,
-  EMPTY_OBJ,
-  EMPTY_ARR
-} from '@vue/shared'
+import { isString, isArray, EMPTY_OBJ, EMPTY_ARR } from '@vue/shared'
 import {
   TEXT,
   CLASS,
@@ -35,6 +28,7 @@ import { queueJob, queuePostFlushCb, flushPostFlushCbs } from './scheduler'
 import { effect, stop, ReactiveEffectOptions } from '@vue/observer'
 import { resolveProps } from './componentProps'
 import { resolveSlots } from './componentSlots'
+import { ELEMENT, STATEFUL_COMPONENT, FUNCTIONAL_COMPONENT } from './shapeFlags'
 
 const prodEffectOptions = {
   scheduler: queueJob
@@ -108,7 +102,7 @@ export function createRenderer(options: RendererOptions) {
     n2: VNode,
     container: HostNode,
     anchor?: HostNode,
-    optimized?: boolean
+    optimized: boolean = false
   ) {
     // patching & not same type, unmount old tree
     if (n1 != null && !isSameType(n1, n2)) {
@@ -117,7 +111,7 @@ export function createRenderer(options: RendererOptions) {
       n1 = null
     }
 
-    const { type } = n2
+    const { type, shapeFlag } = n2
     switch (type) {
       case Text:
         processText(n1, n2, container, anchor)
@@ -132,10 +126,14 @@ export function createRenderer(options: RendererOptions) {
         processPortal(n1, n2, container, anchor, optimized)
         break
       default:
-        if (isString(type)) {
+        if (shapeFlag & ELEMENT) {
           processElement(n1, n2, container, anchor, optimized)
         } else {
-          if (__DEV__ && !isFunction(type) && !isObject(type)) {
+          if (
+            __DEV__ &&
+            !(shapeFlag & STATEFUL_COMPONENT) &&
+            !(shapeFlag & FUNCTIONAL_COMPONENT)
+          ) {
             // TODO warn invalid node type
             debugger
           }
@@ -453,14 +451,14 @@ export function createRenderer(options: RendererOptions) {
     const instance: ComponentInstance = (vnode.component = createComponentInstance(
       Component
     ))
-    instance.update = effect(() => {
-      if (!instance.vnode) {
+    instance.update = effect(function updateComponent() {
+      if (instance.vnode === null) {
         // initial mount
         instance.vnode = vnode
         resolveProps(instance, vnode.props, Component.props)
         resolveSlots(instance, vnode.children)
         // setup stateful
-        if (typeof Component === 'object') {
+        if (vnode.shapeFlag & STATEFUL_COMPONENT) {
           setupStatefulComponent(instance)
         }
         const subTree = (instance.subTree = renderComponentRoot(instance))
diff --git a/packages/runtime-core/src/shapeFlags.ts b/packages/runtime-core/src/shapeFlags.ts
new file mode 100644 (file)
index 0000000..4b75428
--- /dev/null
@@ -0,0 +1,3 @@
+export const ELEMENT = 1
+export const FUNCTIONAL_COMPONENT = 1 << 1
+export const STATEFUL_COMPONENT = 1 << 2
index 728e995eaaefbb386c7970b5ddd85fc39547e6ca..c248a87a3c0b6dfc466eea7818c8d930ab1626ce 100644 (file)
@@ -3,6 +3,7 @@ import { ComponentInstance } from './component'
 import { HostNode } from './createRenderer'
 import { RawSlots } from './componentSlots'
 import { CLASS } from './patchFlags'
+import { ELEMENT, FUNCTIONAL_COMPONENT, STATEFUL_COMPONENT } from './shapeFlags'
 
 export const Fragment = Symbol('Fragment')
 export const Text = Symbol('Text')
@@ -36,6 +37,7 @@ export interface VNode {
   target: HostNode | null // portal target
 
   // optimization only
+  shapeFlag: number
   patchFlag: number
   dynamicProps: string[] | null
   dynamicChildren: VNode[] | null
@@ -93,6 +95,15 @@ export function createVNode(
 ): VNode {
   // Allow passing 0 for props, this can save bytes on generated code.
   props = props || null
+
+  const shapeFlag = isString(type)
+    ? ELEMENT
+    : isFunction(type)
+      ? FUNCTIONAL_COMPONENT
+      : isObject(type)
+        ? STATEFUL_COMPONENT
+        : 0
+
   const vnode: VNode = {
     type,
     props,
@@ -102,6 +113,7 @@ export function createVNode(
     el: null,
     anchor: null,
     target: null,
+    shapeFlag,
     patchFlag,
     dynamicProps,
     dynamicChildren: null
@@ -123,7 +135,12 @@ export function createVNode(
   // component nodes also should always be tracked, because even if the
   // component doesn't need to update, it needs to persist the instance on to
   // the next vnode so that it can be properly unmounted later.
-  if (shouldTrack && (patchFlag || isObject(type) || isFunction(type))) {
+  if (
+    shouldTrack &&
+    (patchFlag ||
+      shapeFlag & STATEFUL_COMPONENT ||
+      shapeFlag & FUNCTIONAL_COMPONENT)
+  ) {
     trackDynamicNode(vnode)
   }