Skip to content

vue 初始化流程

当我们调用createApp时内部调用如下

createApp

ts
export const createApp = (...args) => {
  const app = ensureRenderer().createApp(...args)

  return app
}

ensureRenderer

ts
// packages/runtime-dom/src/index.ts

// lazy create the renderer - this makes core renderer logic tree-shakable
// in case the user only imports reactivity utilities from Vue.
// 延迟创建渲染器 - 如果用户仅从 Vue 导入响应式程序,这会使核心渲染器逻辑可进行摇树优化。
let renderer: Renderer<Element | ShadowRoot> | HydrationRenderer
// l:42
function ensureRenderer() {
  return (
    renderer ||
    (renderer = createRenderer<Node, Element | ShadowRoot>(rendererOptions))
  )
}

createRenderer 内部调用并返回 baseCreateRenderer

ts
//packages/runtime-core/src/renderer.ts:343~2358

function baseCreateRenderer(
  options: RendererOptions,
  createHydrationFns?: typeof createHydrationFunctions
): any {
  // 定义了 以下 函数
  const patch = () => {}
  const processElement = () => {}
  const mountElement = () => {}
  const mountChildren = () => {}
  const patchProps = () => {}
  const processComponent = () => {}
  const mountComponent = () => {}
  const setupRenderEffect = () => {}
  // 根渲染函数
  const render: RootRenderFunction = (vnode, container, isSVG) => {
    if (vnode == null) {
      if (container._vnode) {
        unmount(container._vnode, null, null, true)
      }
    } else {
      patch(container._vnode || null, vnode, container, null, null, null, isSVG)
    }
    flushPostFlushCbs()
    container._vnode = vnode
  }

  return {
    render,
    createApp: createAppAPI(render, hydrate),
  }
}

createAppAPI

ts
// /packages/runtime-core/src/apiCreateApp.ts

let uid = 0

export function createAppAPI<HostElement>(
  render: RootRenderFunction,
  hydrate?: RootHydrateFunction
): CreateAppFunction<HostElement> {
  return function createApp(rootComponent, rootProps = null) {
    const context = createAppContext()
    const installedPlugins = new Set()

    let isMounted = false
    const app = {
      _uid: uid++,
      _component: rootComponent as ConcreteComponent,
      _props: rootProps,
      _container: null,
      _context: context,
      _instance: null,
      get config() {
        return context.config
      },

      set config(v) {
        if (__DEV__) {
          warn(
            `app.config cannot be replaced. Modify individual options instead.`
          )
        }
      },

      use(plugin: Plugin, ...options: any[]) {},
      component(name: string, component?: Component): any {},
      directive(name: string, directive?: Directive) {},
      mount(
        rootContainer: HostElement,
        isHydrate?: boolean,
        isSVG?: boolean
      ): any {
        if (!isMounted) {
          const vnode = createVNode(
            rootComponent as ConcreteComponent,
            rootProps
          )
          // store app context on the root VNode.
          // this will be set on the root instance on initial mount.
          vnode.appContext = context

          //  通过闭包,柯里化函数 存储了render
          render(vnode, rootContainer, isSVG) // vy: 虚拟节点 渲染为 真实节点

          isMounted = true

          app._container = rootContainer

          return getExposeProxy(vnode.component!) || vnode.component!.proxy
        }
      },
    }

    return app
  }
}

createVNode

ts
// http://localhost:52330/packages/runtime-core/src/vnode.ts

function createBaseVNode() {
  const vnode = {
    __v_isVNode: true,
    __v_skip: true,
    type,
    props,
    key: props && normalizeKey(props),
    ref: props && normalizeRef(props),
    scopeId: currentScopeId,
    slotScopeIds: null,
    children,
    component: null,
    suspense: null,
    ssContent: null,
    ssFallback: null,
    dirs: null,
    transition: null,
    el: null,
    anchor: null,
    target: null,
    targetAnchor: null,
    staticCount: 0,
    shapeFlag,
    patchFlag,
    dynamicProps,
    dynamicChildren: null,
    appContext: null,
  } as VNode

  return vnode
}

app.mount() -> 根 render-> patch -> processComponent -> mountComponent ↓ -> createComponentInstance -> setupComponent(instance) -> setupRenderEffect(组件实例,初始虚拟节点)

setupRenderEffect -> componentUpdateFn 创建组件实例 调用生命周期函数 beforeMounted -> instance.subTree = renderComponentRoot(instance) -> 调用组件 render 生成虚拟节点 vnode 并返回赋值给 subtree 再进行 patch( null, subTree, container, anchor, instance, parentSuspense, isSVG )

shapeFlag = 17 processElement() mountElement() CreateElement mountChildren() 深度优先遍历 组件生命周期函数 mounted insert() 结束

Released under the MIT License.