wip: optimize w/ shapeFlag
This commit is contained in:
parent
b77709286f
commit
2f1f6b4355
@ -70,10 +70,13 @@ function run(effect: ReactiveEffect, fn: Function, args: any[]): any {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function cleanup(effect: ReactiveEffect) {
|
export function cleanup(effect: ReactiveEffect) {
|
||||||
for (let i = 0; i < effect.deps.length; i++) {
|
const { deps } = effect
|
||||||
effect.deps[i].delete(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(
|
export function track(
|
||||||
|
@ -5,11 +5,12 @@ import {
|
|||||||
observable,
|
observable,
|
||||||
immutable
|
immutable
|
||||||
} from '@vue/observer'
|
} from '@vue/observer'
|
||||||
import { isFunction, EMPTY_OBJ } from '@vue/shared'
|
import { EMPTY_OBJ } from '@vue/shared'
|
||||||
import { RenderProxyHandlers } from './componentProxy'
|
import { RenderProxyHandlers } from './componentProxy'
|
||||||
import { ComponentPropsOptions, ExtractPropTypes } from './componentProps'
|
import { ComponentPropsOptions, ExtractPropTypes } from './componentProps'
|
||||||
import { PROPS, DYNAMIC_SLOTS, FULL_PROPS } from './patchFlags'
|
import { PROPS, DYNAMIC_SLOTS, FULL_PROPS } from './patchFlags'
|
||||||
import { Slots } from './componentSlots'
|
import { Slots } from './componentSlots'
|
||||||
|
import { STATEFUL_COMPONENT } from './shapeFlags'
|
||||||
|
|
||||||
export type Data = { [key: string]: any }
|
export type Data = { [key: string]: any }
|
||||||
|
|
||||||
@ -148,16 +149,17 @@ export function setupStatefulComponent(instance: ComponentInstance) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function renderComponentRoot(instance: ComponentInstance): VNode {
|
export function renderComponentRoot(instance: ComponentInstance): VNode {
|
||||||
const { type: Component, renderProxy } = instance
|
const { type: Component, vnode } = instance
|
||||||
if (isFunction(Component)) {
|
if (vnode.shapeFlag & STATEFUL_COMPONENT) {
|
||||||
return normalizeVNode(Component(instance))
|
if (__DEV__ && !(Component as any).render) {
|
||||||
} else {
|
|
||||||
if (__DEV__ && !Component.render) {
|
|
||||||
// TODO warn missing render
|
// TODO warn missing render
|
||||||
}
|
}
|
||||||
return normalizeVNode(
|
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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,14 +14,7 @@ import {
|
|||||||
createComponentInstance,
|
createComponentInstance,
|
||||||
setupStatefulComponent
|
setupStatefulComponent
|
||||||
} from './component'
|
} from './component'
|
||||||
import {
|
import { isString, isArray, EMPTY_OBJ, EMPTY_ARR } from '@vue/shared'
|
||||||
isString,
|
|
||||||
isArray,
|
|
||||||
isFunction,
|
|
||||||
isObject,
|
|
||||||
EMPTY_OBJ,
|
|
||||||
EMPTY_ARR
|
|
||||||
} from '@vue/shared'
|
|
||||||
import {
|
import {
|
||||||
TEXT,
|
TEXT,
|
||||||
CLASS,
|
CLASS,
|
||||||
@ -35,6 +28,7 @@ import { queueJob, queuePostFlushCb, flushPostFlushCbs } from './scheduler'
|
|||||||
import { effect, stop, ReactiveEffectOptions } from '@vue/observer'
|
import { effect, stop, ReactiveEffectOptions } from '@vue/observer'
|
||||||
import { resolveProps } from './componentProps'
|
import { resolveProps } from './componentProps'
|
||||||
import { resolveSlots } from './componentSlots'
|
import { resolveSlots } from './componentSlots'
|
||||||
|
import { ELEMENT, STATEFUL_COMPONENT, FUNCTIONAL_COMPONENT } from './shapeFlags'
|
||||||
|
|
||||||
const prodEffectOptions = {
|
const prodEffectOptions = {
|
||||||
scheduler: queueJob
|
scheduler: queueJob
|
||||||
@ -108,7 +102,7 @@ export function createRenderer(options: RendererOptions) {
|
|||||||
n2: VNode,
|
n2: VNode,
|
||||||
container: HostNode,
|
container: HostNode,
|
||||||
anchor?: HostNode,
|
anchor?: HostNode,
|
||||||
optimized?: boolean
|
optimized: boolean = false
|
||||||
) {
|
) {
|
||||||
// patching & not same type, unmount old tree
|
// patching & not same type, unmount old tree
|
||||||
if (n1 != null && !isSameType(n1, n2)) {
|
if (n1 != null && !isSameType(n1, n2)) {
|
||||||
@ -117,7 +111,7 @@ export function createRenderer(options: RendererOptions) {
|
|||||||
n1 = null
|
n1 = null
|
||||||
}
|
}
|
||||||
|
|
||||||
const { type } = n2
|
const { type, shapeFlag } = n2
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Text:
|
case Text:
|
||||||
processText(n1, n2, container, anchor)
|
processText(n1, n2, container, anchor)
|
||||||
@ -132,10 +126,14 @@ export function createRenderer(options: RendererOptions) {
|
|||||||
processPortal(n1, n2, container, anchor, optimized)
|
processPortal(n1, n2, container, anchor, optimized)
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
if (isString(type)) {
|
if (shapeFlag & ELEMENT) {
|
||||||
processElement(n1, n2, container, anchor, optimized)
|
processElement(n1, n2, container, anchor, optimized)
|
||||||
} else {
|
} else {
|
||||||
if (__DEV__ && !isFunction(type) && !isObject(type)) {
|
if (
|
||||||
|
__DEV__ &&
|
||||||
|
!(shapeFlag & STATEFUL_COMPONENT) &&
|
||||||
|
!(shapeFlag & FUNCTIONAL_COMPONENT)
|
||||||
|
) {
|
||||||
// TODO warn invalid node type
|
// TODO warn invalid node type
|
||||||
debugger
|
debugger
|
||||||
}
|
}
|
||||||
@ -453,14 +451,14 @@ export function createRenderer(options: RendererOptions) {
|
|||||||
const instance: ComponentInstance = (vnode.component = createComponentInstance(
|
const instance: ComponentInstance = (vnode.component = createComponentInstance(
|
||||||
Component
|
Component
|
||||||
))
|
))
|
||||||
instance.update = effect(() => {
|
instance.update = effect(function updateComponent() {
|
||||||
if (!instance.vnode) {
|
if (instance.vnode === null) {
|
||||||
// initial mount
|
// initial mount
|
||||||
instance.vnode = vnode
|
instance.vnode = vnode
|
||||||
resolveProps(instance, vnode.props, Component.props)
|
resolveProps(instance, vnode.props, Component.props)
|
||||||
resolveSlots(instance, vnode.children)
|
resolveSlots(instance, vnode.children)
|
||||||
// setup stateful
|
// setup stateful
|
||||||
if (typeof Component === 'object') {
|
if (vnode.shapeFlag & STATEFUL_COMPONENT) {
|
||||||
setupStatefulComponent(instance)
|
setupStatefulComponent(instance)
|
||||||
}
|
}
|
||||||
const subTree = (instance.subTree = renderComponentRoot(instance))
|
const subTree = (instance.subTree = renderComponentRoot(instance))
|
||||||
|
3
packages/runtime-core/src/shapeFlags.ts
Normal file
3
packages/runtime-core/src/shapeFlags.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export const ELEMENT = 1
|
||||||
|
export const FUNCTIONAL_COMPONENT = 1 << 1
|
||||||
|
export const STATEFUL_COMPONENT = 1 << 2
|
@ -3,6 +3,7 @@ import { ComponentInstance } from './component'
|
|||||||
import { HostNode } from './createRenderer'
|
import { HostNode } from './createRenderer'
|
||||||
import { RawSlots } from './componentSlots'
|
import { RawSlots } from './componentSlots'
|
||||||
import { CLASS } from './patchFlags'
|
import { CLASS } from './patchFlags'
|
||||||
|
import { ELEMENT, FUNCTIONAL_COMPONENT, STATEFUL_COMPONENT } from './shapeFlags'
|
||||||
|
|
||||||
export const Fragment = Symbol('Fragment')
|
export const Fragment = Symbol('Fragment')
|
||||||
export const Text = Symbol('Text')
|
export const Text = Symbol('Text')
|
||||||
@ -36,6 +37,7 @@ export interface VNode {
|
|||||||
target: HostNode | null // portal target
|
target: HostNode | null // portal target
|
||||||
|
|
||||||
// optimization only
|
// optimization only
|
||||||
|
shapeFlag: number
|
||||||
patchFlag: number
|
patchFlag: number
|
||||||
dynamicProps: string[] | null
|
dynamicProps: string[] | null
|
||||||
dynamicChildren: VNode[] | null
|
dynamicChildren: VNode[] | null
|
||||||
@ -93,6 +95,15 @@ export function createVNode(
|
|||||||
): VNode {
|
): VNode {
|
||||||
// Allow passing 0 for props, this can save bytes on generated code.
|
// Allow passing 0 for props, this can save bytes on generated code.
|
||||||
props = props || null
|
props = props || null
|
||||||
|
|
||||||
|
const shapeFlag = isString(type)
|
||||||
|
? ELEMENT
|
||||||
|
: isFunction(type)
|
||||||
|
? FUNCTIONAL_COMPONENT
|
||||||
|
: isObject(type)
|
||||||
|
? STATEFUL_COMPONENT
|
||||||
|
: 0
|
||||||
|
|
||||||
const vnode: VNode = {
|
const vnode: VNode = {
|
||||||
type,
|
type,
|
||||||
props,
|
props,
|
||||||
@ -102,6 +113,7 @@ export function createVNode(
|
|||||||
el: null,
|
el: null,
|
||||||
anchor: null,
|
anchor: null,
|
||||||
target: null,
|
target: null,
|
||||||
|
shapeFlag,
|
||||||
patchFlag,
|
patchFlag,
|
||||||
dynamicProps,
|
dynamicProps,
|
||||||
dynamicChildren: null
|
dynamicChildren: null
|
||||||
@ -123,7 +135,12 @@ export function createVNode(
|
|||||||
// component nodes also should always be tracked, because even if the
|
// 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
|
// 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.
|
// 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)
|
trackDynamicNode(vnode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user