〖Vue3 源码笔记02〗运行轨迹

createApp位置

vue/src/index.ts => runtime-dom => createApp

// vue/src/index.ts

export { compileToFunction as compile }
export * from '@vue/runtime-dom'
复制代码
// runtime-dom/src/index.ts
import {
  createRenderer,
  createHydrationRenderer,
  warn,
  RootRenderFunction,
  CreateAppFunction,
  Renderer,
  HydrationRenderer,
  App,
  RootHydrateFunction,
  isRuntimeOnly,
  DeprecationTypes,
  compatUtils
} from '@vue/runtime-core'

export const createApp = ((...args) => {
  const app = ensureRenderer().createApp(...args)
  ...
  return app
}
复制代码

寻找state

ensureRenderer() => return createRenderer() => return baseCreateRenderer() =>

return {
    render,
    hydrate,
    createApp: createAppAPI(render, hydrate)
  }
复制代码

=> createAppAPI()

打印一下

app instance
image.png image.png

state暴露在mount返回的实例,与vue2不同。app状态,data为函数(只能为Function)还未运行暴露。

mount

// mount
const vnode = createVNode(
    rootComponent as ConcreteComponent,
    rootProps
  )
vnode.appContext = context

render(vnode, rootContainer, isSVG)

isMounted = true
app._container = rootContainer

return getExposeProxy(vnode.component!) || vnode.component!.proxy
// 这里返回的是 vnode.component!.proxy
复制代码

PublicInstanceProxyHandlers

直接看proxy handler,找到packages\runtime-core\src\componentPublicInstance.ts

export const PublicInstanceProxyHandlers: ProxyHandler<any> = {
    get({ _: instance }: ComponentRenderContext, key: string) {
        ...
    },
    
    set({ _: instance }: ComponentRenderContext, key: string, value: any): boolean {
        ...
        },
        
    has({ _: { data, setupState, accessCache, ctx, appContext, propsOptions }}: ComponentRenderContext, key: string) {
        ...
    }
}
复制代码

试图溯源

回到第一个版本 v3.0.0-alpha.0

从readme到 Contributing Guide

Development Setup

$ yarn # install the dependencies of the project
复制代码

A high level overview of tools used:

oho, npm run dev报错compiler-ssr不存在package.json文件,修复?可能还有一些问题,那还是跳版本v3.0.0-alpha.1,依然报错。那直接v3.0.0

// 总是会在这报错
const pkg = require(`../packages/${f}/package.json`)
// 为什么尤大没问题呢?是node版本问题吗?
复制代码

算了算了 继续 看v3.2.20

createApp

// packages\runtime-dom\src\index.ts
export const createApp = ((...args) => {
  const app = ensureRenderer().createApp(...args)
  
  app.mount = (containerOrSelector: Element | ShadowRoot | string): any => {
    const container = normalizeContainer(containerOrSelector)
    if (!container) return

    container.innerHTML = ''
    const proxy = mount(container, false, container instanceof SVGElement)
    if (container instanceof Element) {
      container.removeAttribute('v-cloak')
      container.setAttribute('data-v-app', '')
    }
    return proxy
  }
  
  return app
}
复制代码

createVNode

// packages\runtime-core\src\apiCreateApp.ts
// createAppAPI() => return createApp()
mount() {
  const vnode = createVNode(rootComponent)
  return vnode.component!.proxy
}
复制代码
// packages\runtime-core\src\vnode.ts

// 判断入口
export const createVNode = (
  __DEV__ ? createVNodeWithArgsTransform : _createVNode
) as typeof _createVNode

// 拦截、调整参数、最后传递 createBaseVNode
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
): VNode{
    if (!type || type === NULL_DYNAMIC_COMPONENT){...}
    if (isVNode(type)){...}
    if (isClassComponent(type)) {}
    
    return createBaseVNode(
        type,
        props,
        children,
        patchFlag,
        dynamicProps,
        shapeFlag,
        isBlockNode,
        true
      )
}
复制代码

render

初始化时vnode不存在component,然后带着type进入render

//packages\runtime-core\src\renderer.ts
const render: RootRenderFunction = (vnode, container, isSVG) => {
    patch(container._vnode || null, vnode, container, null, null, null, isSVG)
    flushPostFlushCbs()
    container._vnode = vnode
}
复制代码

patch

patch => processComponent => mountComponent => setupRenderEffect

// packages\runtime-core\src\renderer.ts
const effect = new ReactiveEffect(
      componentUpdateFn,
      () => queueJob(instance.update),
      instance.scope // track it in component's effect scope
    )
复制代码
// packages\reactivity\src\effect.ts
export class ReactiveEffect<T = any> {
active = true
  deps: Dep[] = []

  // can be attached after creation
  computed?: boolean
  allowRecurse?: boolean
  onStop?: () => void
  
  constructor(
    public fn: () => T,
    public scheduler: EffectScheduler | null = null,
    scope?: EffectScope | null
  ) {
    recordEffectScope(this, scope)
  }
  
  run() {}
  stop() {}
}
复制代码

effect

最终将函数 componentUpdateFn 传递给 effect ,再进入track循环

Guess you like

Origin juejin.im/post/7035462914945318943