vue3整体流程梳理(初次挂载)

461 阅读10分钟

前言

vue3发布至今将近一年时间,一直没有使用的机会,公司使用的技术栈是vue2,因此做一下记录,希望能对大家有帮助,有不对的地方请指正,共同进步。

示例代码

还是先来看下vue3对于options api是如何处理的,以下代码是从vue3源码里粘出来的demo

<script type="text/x-template" id="template">
  <table v-if="filteredData.length">
    <thead>
      <tr>
        <td v-for="key in cloumns" click="sortBy(key)">
          {{capitalize(key)}}
        </td>
      </tr>
    </thead>
    <tbody>
      <tr v-for="entry in filteredData">
        <td v-for="key in columns">
          {{entry[key]}}
        </td>
      </tr>
    </tbody>
  </table>
</script>

<script>
const DemoGride = {
  template: '#template',
  props: {
    data: Array,
    columns: Array,
    filterKey: String
  },
  data() {
    return {
      sortKey: '',
      sortOrders: this.columns.reduce((o, key) => (o[key] = 1, o), {})
    }
  },
  computed: {
    filteredData() {
      const sortKey = this.sortKey
      const filterKey = this.filterKey && this.filterKey.toLowerCase()
      const order = this.sortOrders[sortKey] || 1
      let data = this.data
      if (filterKey) {
        data = data.filter(row => {
          return Object.keys(row).some(key => {
            return String(row[key]).toLowerCase().indexOf(filterKey) > -1
          })
        })
      }
      if (sortKey) {
        data = data.slice().sort((a, b) => {
          a = a[sortKey]
          b = b[sortKey]
          return (a === b ? 0 : a > b ? 1 : -1) * order
        })
      }
      return data
    }
  },
  methods: {
    sortBy(key) {
      this.sortKey = key
      this.sortOrders[key] = this.sortOrders[key] * -1
    },
    capitalize(str) {
      return str.charAt(0).toUpperCase() + str.slice(1)
    }
  }
}
</script>
<div id="demo">
  <form id="search">
    Search <input name="query" v-model="searchQuery">
  </form>
  <demo-grid
    :data="gridData"
    :columns="gridColumns"
    :filter-key="searchQuery">
  </demo-grid>
</div>
<script>
Vue.createApp({
  components: {
    DemoGrid
  },
  data: () => ({
    searchQuery: '',
    gridColumns: ['name', 'power'],
    gridData: [
      { name: 'Chuck Norris', power: Infinity },
      { name: 'Bruce Lee', power: 9000 },
      { name: 'Jackie Chan', power: 7000 },
      { name: 'Jet Li', power: 8000 }
    ]
  })
}).mount('#demo')
</script>

接下来我们来看看createApp都做了哪些工作

createApp

ensureRenderer最终会定位baseCreateRenderer方法上

// packages/runtime-dom/src/index.ts
export const createApp = ((...args)) => {
  // ensureRenderer()执行后会得到{render,hydrate,createApp: createAppAPI(render,hydrate)}
  const app = ensureRenderer().createApp(...args)
  const { mount } = app
  app.mount = (containerOrSelector) => {
      // 获取dom节点
      const container = normalizeContainer(containerOrSelector)
      const component = app._component
      component.template = container.innerHTML
      container.innerHTML = ''
      const proxy = mount(container, false, container instanceof SVGElement)
      return proxy
  }
  return app
}

baseCreateRenderer

方法内会定义好诸多渲染相关的方法,看名字就能猜到是干嘛的

// packages/runtime-core/src/renderer.ts
function baseCreateRenderer(
  options: RendererOptions,
  createHydrationFns?:typeof createHydrationFunctions
){
  const patch:patchFn = (...args) => {}
  const processText: processTextOrCommentFn = (...args) => {}
  const processCommentNode: processTextOrCommentFn = (...args) => {}
  const mountStaticNode = (...args) => {}
  const patchStaticNode = (...args) => {}
  const moveStaticNode = (...args) => {}
  const removeStaticNode = (...args) => {}
  const processElement = (...args) => {}
  const mountElement = (...args) => {}
  const setScopeId = (...args) => {}
  const mountChildren: mountChildrenFn = (...args) => {}
  const patchBlockChildren:patchBlockChildrenFn = (...args) => {}
  const patchProps = (...args) => {}
  const processFragment = (...args) => {}
  const processComponent = (...args) => {}
  const updateComponent = (...args) => {}
  const setupRenderEffect: setupRenderEffectFn = (...args) => {}
  const updateComponentPreRender = (...args) => {}
  const patchChildren:patchChildrenFn = (...args) => {}
  const patchUnkeyedChildren = (...args) => {}
  const patchKeyedChildren = (...args) => {}
  const move = (...args) => {}
  const unmount = (...args) => {}
  const remove = (...args) => {}
  const removeFragment = (...args) => {}
  const unmountComponent = (...args) => {}
  const unmountChildren = (...args) => {}
  const render = (...args) => {}
  const internals = (...args) => {}
  return {
    render,
    hydrate,
    createApp: createAppAPI(render, hydrate)
  }
}

接下来看下createAppAPI里做了什么

createAppAPI

// packages/runtime-core/src/apiCreateApp.ts
export function createAppAPI(
  render:RootRenderFunction,
  hydrate?:RootHydrateFunction
){
  return function createApp(rootComponent, rootProps = null){
    // 返回一个应用上下文
    const context = createAppContext()
    // 创建app实例
    const app: App = (context.app = {
      _uid: uid++,
      _component: rootComponent as ConcreteComponent,
      _props: rootProps,
      _container: null,
      _context: context,
      _instance: null,
      version,
      get config(){},
      set config(){},
      // 安装插件,use(store),use(vueRouter)
      use(plugin:Plugin,...options:any[]){},
      // 混入相关
      mixin(mixin: ComponentOptions){},
      // 组件
      component(name:string,component?:Component){},
      // 指令
      directive(name:string, directive:Directive){},
      // 挂载
      mount(rootContainer:HostElement,isHydrate?:boolean,isSVG?:boolean){

      },
      // 卸载
      unmount(){},
      // provide
      provide(key,value){}

    })
  }
}

createAppContext()创建应用上下文

function createAppContext(){
  return {
    // 应用实例
    app: null as any,
    // 配置项
    config: {
      isNativeTag: NO,
      performance: false,
      globalProperties: {},
      optionMergeStrategies: {},
      errorHandler: undefined,
      warnHandler: undefined,
      compilerOptions: {}
    },
    // 混入相关
    mixins: [],
    // 组件
    components: {},
    // 指令
    directives: {},
    provides: Object.create(null),
    optionsCache: new WeakMap(),
    propsCache: new WeakMap(),
    emitsCache: new WeakMap()
  }
}

createApp的任务就是创建一个app实例,并定义好use、mixins、components、directives等全局方法以及mount方法,接下来我们看下mount做了哪些事情。

mount

mount方法是定义在app实例上的

// packages/runtime-core/src/apiCreateApp.ts
export function createAppAPI(...){
    return function createApp(rootComponent,rootProps=null){
        const context = createAppContext()
        const app: App = (context.app = {
            ...
             mount(rootContainer: HostElement,isHydrate?: boolean,isSVG?: boolean){
                 if(!isMounted){
                     // rootComponent 就是options config
                     // 这里的vnode是组件的vnode,不是dom的vnode
                     const vnode = createVNode(
                        rootComponent as ConcreteComponent,
                        rootProps
                      )
                      if (isHydrate && hydrate) {
                        hydrate(vnode as VNode<Node, Element>, rootContainer as any)
                      } else {
                        // render方法是在baseCreateRenderer函数里定义好的
                        render(vnode, rootContainer, isSVG)
                      }
                 }
             }
            ...
        })
    }
}

mount 函数做的事情
1、创建组件的vnode
2、执行render函数

createVNode

// packages/runtime-core/src/vnode.ts
function _createVNode(
  type: VNodeTypes | ClassComponent | typeof NULL_DYNAMIC_COMPONENT,
  props: (Data & VNodeProps) | null = null,
  children: unknown = null,
  patchFlag: number = 0,
  dynamicProps: string[] | null = null,
  isBlockNode = false
){
  //如果type为空会得到一个symbol类型的对象 const Comment= Symbol(__DEV__?'comment':undeined)
  if (!type || type === NULL_DYNAMIC_COMPONENT) {
    type = Comment
  }
  if(isVNode(type)){
    // 如果type是vnode,在克隆过程中合并引用,而不是覆盖它
    // <component :is="vnode">
    const cloned = cloneVNode(type, props, true /* mergeRef: true */)
    if (children) {
      normalizeChildren(cloned, children)
    }
    return cloned
  }
  // 如果是类组件,__vccOpts为true
  if (isClassComponent(type)) {
    type = type.__vccOpts
  }
   // 2.x async/functional component compat
  if (__COMPAT__) {
    type = convertLegacyComponent(type, currentRenderingInstance)
  }
  // class & style normalization.
  // class 和 style 的标准化,处理在vue中 class=['a'] class={} 等多种情况
  if (props) {
    // for reactive or proxy objects, we need to clone it to enable mutation.
    if (isProxy(props) || InternalObjectKey in props) {
      props = extend({}, props)
    }
    let { class: klass, style } = props
    if (klass && !isString(klass)) {
      props.class = normalizeClass(klass)
    }
    if (isObject(style)) {
      // reactive state objects need to be cloned since they are likely to be
      // mutated
      if (isProxy(style) && !isArray(style)) {
        style = extend({}, style)
      }
      props.style = normalizeStyle(style)
    }
  }
  // 标识当前组件vnode的类型
  const shapeFlag = isString(type)
    ? ShapeFlags.ELEMENT
    : __FEATURE_SUSPENSE__ && isSuspense(type)
      ? ShapeFlags.SUSPENSE
      : isTeleport(type)
        ? ShapeFlags.TELEPORT
        : isObject(type)
          ? ShapeFlags.STATEFUL_COMPONENT
          : isFunction(type)
            ? ShapeFlags.FUNCTIONAL_COMPONENT
            : 0
   // 定义vnode
   const vnode: VNode = {
    __v_isVNode: true,
    __v_skip: true,
    type,
    props,
    key: props && normalizeKey(props),
    ref: props && normalizeRef(props),
    scopeId: currentScopeId,
    slotScopeIds: null,
    children: null,
    component: null,
    suspense: null,
    ssContent: null,
    ssFallback: null,
    dirs: null,
    transition: null,
    el: null,
    anchor: null,
    target: null,
    targetAnchor: null,
    shapeFlag,
    patchFlag,
    dynamicProps,
    dynamicChildren: null,
    appContext: null
  }
  // 处理children
  normalizeChildren(vnode, children)
  // 在3.0里有Block Tree的概念,为了解决2.0diff低效的问题,在每个Block下都有dynamicChildren,在vnode/Block创建阶段时会将当前block区域内的动态内容收集并填充到dynamicChildren,render执行完后,每个block下的动态内容都会被收集到各自的block中,在diff时不再需要对比整棵树,只需要对比同级block下的dynamicChildren即可。
  if (
    isBlockTreeEnabled > 0 &&
    !isBlockNode &&
    // has current parent block
    currentBlock &&
    (patchFlag > 0 || shapeFlag & ShapeFlags.COMPONENT) &&
    patchFlag !== PatchFlags.HYDRATE_EVENTS
  ) {
    currentBlock.push(vnode)
  }

  if (__COMPAT__) {
    convertLegacyVModelProps(vnode)
    convertLegacyRefInFor(vnode)
    defineLegacyVNodeProperties(vnode)
  }
  return vnode
}

createVNode函数做的事情
1、处理class、style以及children
2、创建vnode,并打上shapeFlag标识当前组件的类型
3、blockTree的收集工作

render

// packages/runtime-core/src/renderer.ts
function baseCreateRenderer(
  options: RendererOptions,
  createHydrationFns?:typeof createHydrationFunctions
){
    ...
    const render(vnode, container, isSVG){
        if(vnode == null){
            //vnode为空执行卸载的工作
            if(container._vnode){
                unmount(container._vnode, null, null, true)
            }
        }else {
            // 进行打补丁操作
            patch(container._vnode||null, vnode, container, null, null, null, isSVG)
        }
        // 执行后置的回调任务队列
        flushPostFlushCbs()
    }
    ...
}

render函数做的事情
1、执行patch操作
2、执行后置的回调任务

patch

接下来看patch内是如何进行打补丁的工作,渲染的相关方法是定义在baseCreateRenderer方法内patch也在其中

// packages/runtime-core/src/renderer.ts
function baseCreateRenderer(
  options: RendererOptions,
  createHydrationFns?:typeof createHydrationFunctions
){
    ...
    const render = (vnode,container,isSVG) => {...}
    const patch = (
        n1,
        n2,
        container,
        anchor = null,
        parentComponent = null,
        parentSuspense = null,
        isSVG = false,
        slotScopeIds = null,
        optimized = false
    ) => {
        // 特殊标签会跳出优化
        if (n2.patchFlag === PatchFlags.BAIL) {
          optimized = false
          n2.dynamicChildren = null
        }
        // type是我们传递的options 配置,shapeFlag是创建组件vnode时候打上的标识
        const { type, ref, shapeFlag } = n2
        //例子里传递的是options,打上的shapeFlag是4,因此会执行processComponent方法
        switch (type) {
          case Text:
            processText(n1, n2, container, anchor)
            break
          case Comment:
            processCommentNode(n1, n2, container, anchor)
            break
          case Static:
            if (n1 == null) {
              mountStaticNode(n2, container, anchor, isSVG)
            } else if (__DEV__) {
              patchStaticNode(n1, n2, container, isSVG)
            }
            break
          case Fragment:
            processFragment(...)
            break
          default:
            if (shapeFlag & ShapeFlags.ELEMENT) {
              processElement(...)
            } else if (shapeFlag & ShapeFlags.COMPONENT) {
              processComponent(
                n1,
                n2,
                container,
                anchor,
                parentComponent,
                parentSuspense,
                isSVG,
                slotScopeIds,
                optimized
              )
            } else if (shapeFlag & ShapeFlags.TELEPORT) {
              ;(type as typeof TeleportImpl).process(...)
            } else if (__FEATURE_SUSPENSE__ && shapeFlag & ShapeFlags.SUSPENSE) {
              ;(type as typeof SuspenseImpl).process(...)
            } else if (__DEV__) {
              warn('Invalid VNode type:', type, `(${typeof type})`)
            }
        }
    }
    ...
}

patch方法做的事情
1、根据type和shapeFlag来选择对应的处理方法

processComponent

渲染的相关方法是定义在baseCreateRenderer方法内processComponent也在其中

// packages/runtime-core/src/renderer.ts
function baseCreateRenderer(
  options: RendererOptions,
  createHydrationFns?:typeof createHydrationFunctions
){
    ...
    const render = (vnode,container,isSVG) => {...}
    const patch = (...) => {...}
    const processComponent = (
         n1: VNode | null,
        n2: VNode,
        container: RendererElement,
        anchor: RendererNode | null,
        parentComponent: ComponentInternalInstance | null,
        parentSuspense: SuspenseBoundary | null,
        isSVG: boolean,
        slotScopeIds: string[] | null,
        optimized: boolean
    ) => {
        if (n1 == null) {
          if (n2.shapeFlag & ShapeFlags.COMPONENT_KEPT_ALIVE) {
              // keep-alive
            ;(parentComponent!.ctx as KeepAliveContext).activate(
              n2,
              container,
              anchor,
              isSVG,
              optimized
            )
          } else {
            // 挂载组件
            mountComponent(
              n2,
              container,
              anchor,
              parentComponent,
              parentSuspense,
              isSVG,
              optimized
            )
          }
        } else {
            // 更新组件
          updateComponent(n1, n2, optimized)
        }
    }

processComponent方法做的事情
1、判断oldVnode,有值就更新组件,没值就挂载组件

mountComponent

渲染的相关方法是定义在baseCreateRenderer方法内processComponent也在其中

// packages/runtime-core/src/renderer.ts
function baseCreateRenderer(
  options: RendererOptions,
  createHydrationFns?:typeof createHydrationFunctions
){
    ...
    const render = (vnode,container,isSVG) => {...}
    const patch = (...) => {...}
    const processComponent = (...) => {...}
    const mountComponent = (
        initialVNode,
        container,
        anchor,
        parentComponent,
        parentSuspense,
        isSVG,
        optimized
    ) => {
        //获取组件实例
        const instance = compatMountInstance 
            || (initialVNode.component = createComponentInstance(
                initialVNode,
                parentComponent,
                parentSuspense
              ))
         // inject renderer internals for keepAlive
        // 为keep-alive注入渲染器
        if (isKeepAlive(initialVNode)) {
          ;(instance.ctx as KeepAliveContext).renderer = internals
        }
        // resolve props and slots for setup context
        if (!(__COMPAT__ && compatMountInstance)) {
          // 渲染之前用做的事情都会在这里进行,比如props、slots处理,状态响应化处理、编译template生成render函数、注册hooks等等
          setupComponent(instance)
        }
        
        setupRenderEffect(
          instance,
          initialVNode,
          container,
          anchor,
          parentSuspense,
          isSVG,
          optimized
        )
    }
}

instance长啥样

let uid = 0
export function createComponentInstance(
  vnode: VNode,
  parent: ComponentInternalInstance | null,
  suspense: SuspenseBoundary | null
) {
  const type = vnode.type as ConcreteComponent
  // inherit parent app context - or - if root, adopt from root vnode
  // 还记得createAppContext创建的上下文吗?里面有全局的mixins、components、directive
  const appContext =
    (parent ? parent.appContext : vnode.appContext) || emptyAppContext
  const instance: ComponentInternalInstance = {
    uid: uid++,
    vnode,
    type,
    parent,
    appContext,
    root: null!, // to be immediately set
    next: null,
    subTree: null!, // will be set synchronously right after creation
    update: null!, // will be set synchronously right after creation
    render: null,
    proxy: null,
    exposed: null,
    exposeProxy: null,
    withProxy: null,
    effects: null,
    provides: parent ? parent.provides : Object.create(appContext.provides),
    accessCache: null!,
    renderCache: [],

    // local resovled assets
    components: null,
    directives: null,

    // resolved props and emits options
    propsOptions: normalizePropsOptions(type, appContext),
    emitsOptions: normalizeEmitsOptions(type, appContext),

    // emit
    emit: null as any, // to be set immediately
    emitted: null,

    // props default value
    propsDefaults: EMPTY_OBJ,

    // inheritAttrs
    inheritAttrs: type.inheritAttrs,

    // state
    ctx: EMPTY_OBJ,
    data: EMPTY_OBJ,
    props: EMPTY_OBJ,
    attrs: EMPTY_OBJ,
    slots: EMPTY_OBJ,
    refs: EMPTY_OBJ,
    setupState: EMPTY_OBJ,
    setupContext: null,

    // suspense related
    suspense,
    suspenseId: suspense ? suspense.pendingId : 0,
    asyncDep: null,
    asyncResolved: false,

    // lifecycle hooks
    // not using enums here because it results in computed properties
    isMounted: false,
    isUnmounted: false,
    isDeactivated: false,
    bc: null,
    c: null,
    bm: null,
    m: null,
    bu: null,
    u: null,
    um: null,
    bum: null,
    da: null,
    a: null,
    rtg: null,
    rtc: null,
    ec: null,
    sp: null
  }
  if (__DEV__) {
    instance.ctx = createRenderContext(instance)
  } else {
    instance.ctx = { _: instance }
  }
  instance.root = parent ? parent.root : instance
  instance.emit = emit.bind(null, instance)

  return instance

}

setupComponent

// packages/runtime-core/src/components.ts
export function setupComponent(instance, isSSR){
  isInSSRComponentSetup = isSSR
  const { props, children } = instance.vnode
  const isStateful = isStatefulComponent(instance)
  // props
  initProps(instance, props, isStateful, isSSR)
  // slots处理
  initSlots(instance, children)
  const setupResult = isStateful
    ? setupStatefulComponent(instance, isSSR)
    : undefined
  isInSSRComponentSetup = false
  return setupResult
}

setupComponent方法做的事情
1、props、slots处理
2、处理有状态的组件

setupStatefulComponent

// packages/runtime-core/src/components.ts
function setupStatefulComponent(
  instance: ComponentInternalInstance,
  isSSR: boolean
) {
    const Component = instance.type as ComponentOptions
    // 0. create render proxy property access cache
  instance.accessCache = Object.create(null)
   // 1. create public instance / render proxy
  // also mark it raw so it's never observed
  // 为对象增加___v_skip表示当前对象不会被包装成proxy,遇到__v_skip会跳过处理
  instance.proxy = markRaw(new Proxy(instance.ctx, PublicInstanceProxyHandlers))
  // 2. call setup()
  const { setup } = Component
  if(setup){
      // 这里是对composition api的处理
  }else{
      finishComponentSetup(instance, isSSR)
  }
}

setupStatefulComponent方法做的事情
1、composition api的处理
2、调用finishComponentSetup继续处理options api

finishComponentSetup

// packages/runtime-core/src/components.ts
export function finishComponentSetup(
    instance: ComponentInternalInstance,
  isSSR: boolean,
  skipOptions?: boolean
){
    const Component = instance.type as ComponentOptions
    // template / render function normalization
    if(__NODE_JS__ && isSRR){
        // ssr
    }else{
        // 生成渲染vdom用的render函数
        if(compile && !Component.render){
            const template = (_COMPAT_ && instance.vnode.props && instance.vnode.props['inline-template']) || Component.template
            if(template){
                const finalCompilerOptions = extend(
                    extend({isCustomElement,  delimiters},compilerOptions),
                    componentCompilerOptions
                )
                Component.render = compile(template, finalCompilerOptions)
            }
        }
    }
    instance.render = (Component.render || NOOP) as InternalRenderFunction
    // support for 2.x options
    // 处理2.0版的options api
      if (__FEATURE_OPTIONS_API__ && !(__COMPAT__ && skipOptions)) {
        currentInstance = instance
        pauseTracking()
        // 处理生命周期钩子,以及其他方法filter、components、directive
        applyOptions(instance)
        resetTracking()
        currentInstance = null
      }
      
}

finishComponentSetup方法的作用
1、生成render函数
2、兼容2.0的options api

applyOptions
// packages/runtime-core/src/componentOptions.ts
export function applyOptions(instance: ComponentInternalInstance) {
  const options = resolveMergedOptions(instance)
  const publicThis = instance.proxy! as any
  const ctx = instance.ctx
  const {
      data: dataOptions,
      computed,
      methods,
      watch: watchOptions,
      provide:provideOptions,
      inject: injectOptions,
      ...
      components,
      directives,
      filters
  } = options
  if (injectOptions) {
    resolveInjections(injectOptions, ctx, checkDuplicateProperties)
  }
  if(methods){
      // 将method绑到当前实例的上下文上,并将this指向为当前的
      for(const key in methods){
          const methodHandler = methods[key]
          if(isFunction(methodHandler)){
              ctx[key] = mthodHandler.bind(publicThis)
          }
      }
  }
  if(dataOptions){
      const data = (dataOptions as any).call(publicThis, publicThis)
      // data的响应化处理
      instance.data = reactive(data)
  }
  if(computedOptions){
      // 计算属性会生成一个effect,会push到当前实例下的instance.effects,不是存到响应化时get收集时存放的地方
      // 这里是循环computedOptions,因此一个计算属性就是一个effect
      ...
  }
  if(watchOptions){
      // 对于watch处理也是最终会生一个effect,会push到当前实例下的instance.effects,
    for (const key in watchOptions) {
        createWatcher(watchOptions[key], ctx, publicThis, key)
    }
  }
  ....
  //注册生命周期钩子
  registerLifecycleHook(onBeforeMount, beforeMount)
  registerLifecycleHook(onMounted, mounted)
  registerLifecycleHook(onBeforeUpdate, beforeUpdate)
  registerLifecycleHook(onUpdated, updated)
  registerLifecycleHook(onActivated, activated)
  registerLifecycleHook(onDeactivated, deactivated)
  registerLifecycleHook(onErrorCaptured, errorCaptured)
  registerLifecycleHook(onRenderTracked, renderTracked)
  registerLifecycleHook(onRenderTriggered, renderTriggered)
  registerLifecycleHook(onBeforeUnmount, beforeUnmount)
  registerLifecycleHook(onUnmounted, unmounted)
  registerLifecycleHook(onServerPrefetch, serverPrefetch)
  ...
}

applyOptions方法做的事情
1、处理options api
2、注册hook

setupRenderEffect

// packages/runtime-core/src/renderer.ts
function baseCreateRenderer(
  options: RendererOptions,
  createHydrationFns?:typeof createHydrationFunctions
){
    ...
    const render = (vnode,container,isSVG) => {...}
    const patch = (...) => {...}
    const processComponent = (...) => {...}
    const mountComponent = (...) => {...}
    const setupRenderEffect: SetupRenderEffectFn = (
    instance,
    initialVNode,
    container,
    anchor,
    parentSuspense,
    isSVG,
    optimized
  ) => {
      instance.update = effect(function componentEffect(){..})
  }

setupRenderEffect方法做的事情
1、往instance挂载update方法

effect

// packages/reactivity/src/effect.ts
export function effect<T = any>(
  fn: () => T,
  options: ReactiveEffectOptions = EMPTY_OBJ
): ReactiveEffect<T> {
  // 判断是否是effect函数,如果是取出原始值(就是传递进来的fn)
  if (isEffect(fn)) {
    fn = fn.raw
  }
  // 创建新的effect,这个effect就是传进来的fn的执行结果
  const effect = createReactiveEffect(fn, options)
  // computed惰性原因在这里,
  if (!options.lazy) {
    effect()
  }
  return effect
    
}

effect方法做的事情
1、创建一个响应化的effect副作用 2、判断options.lazy是否执行effect

createReactiveEffect
function createReactiveEffect<T = any>(
  fn: () => T,
  options: ReactiveEffectOptions
): ReactiveEffect<T> {
  const effect = function reactiveEffect(): unknown {
    // 如果不是激活状态,执行fn
    if (!effect.active) {
      return fn()
    }
    if (!effectStack.includes(effect)) {
      // 持有当前effect的deps将会删除当前的effect
      cleanup(effect)
      try {
        // 收集依赖,将当前的effect的入栈
        enableTracking()
        // effect入栈
        effectStack.push(effect)
        activeEffect = effect
        return fn()
      } finally {
        effectStack.pop()
        resetTracking()
        activeEffect = effectStack[effectStack.length - 1]
      }
    }
  } as ReactiveEffect
  effect.id = uid++
  effect.allowRecurse = !!options.allowRecurse
  effect._isEffect = true
  effect.active = true
  effect.raw = fn // 创建update方法时传进来的fn
  effect.deps = [] // 持有当前effect的dep数组
  effect.options = options
  return effect
}

执行effect

执行的就是上面createReactiveEffect返回的effect,除了收集effect外,还执行了fn(instance.update(fn)执行的是这个fn),fn的内容请看componentEffect

componentEffect

if(!instance.isMounted){
    const { el, props } = initialVNode
    const { bm, m, parent } = instance
    if (el && hydrateNode){
        ...
    }else{
        // 生成子树结构,执行render函数(手写或者template生成的),生成渲染vnode,经过处理后,此时的instance.vnode的type类型会变为Fragment/Comment/Text/Static,在执行patch时就会进入到相应的方法内开始渲染工作,
        const subTree = (instance.subTree = renderComponentRoot(instance))
        
        // 又跑到了patch的方法内,
        patch(
            null,
            subTree,
            container,
            anchor,
            instance,
            parentSuspense,
            isSVG
          )
    }
}