Vue3源码解读之runtime(上)

Vue3源码解读之runtime(上)前言上一篇文章,我们提到packages中核心的源码主要分为三部分,接下来我们就开始阅读runtime部分的代码createApp(App).mount('#app')接下来我们就以入口文件中的这行代码开始来一步步深入初始化上一篇文章中我们提到vue主入口文件中,引入导出了runtime-dom和compiler,而createApp就是来自runtime-dom// packages/runtime-dom/src/index.tsexport c
摘要由CSDN通过智能技术生成

Vue3源码解读之runtime(上)

前言

上一篇文章,我们提到packages中核心的源码主要分为三部分,接下来我们就开始阅读runtime部分的代码

createApp(App).mount('#app')

接下来我们就以入口文件中的这行代码开始来一步步深入

初始化

上一篇文章中我们提到vue主入口文件中,引入导出了runtime-domcompiler,而createApp就是来自runtime-dom

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

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

  if (__DEV__) {
   
    injectNativeTagCheck(app) // 在dev环境下,注册一个方法isNativeTag,挂载到app.config下面
  }

  const {
    mount } = app
  app.mount = (containerOrSelector: Element | ShadowRoot | string): any => {
   
    // ...
  }

  return app
}) as CreateAppFunction<Element>

在该函数内部中通过调用ensureRenderer()createApp(...args)创建了app实例并把实例返回出去,因此我们可以在app实例中安装插件,设置全局指令等等。这其中又是怎么实现的呢?

创建renderer

ensureRenderer()函数的用途是什么呢?

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

function ensureRenderer() {
   
  return renderer || (renderer = createRenderer<Node, Element>(rendererOptions))
}

我们可以看到调用该函数后返回一个renderer,若没有renderer则调用createRenderer来进行创建。

而这边的createRenderer则是来自runtime-core

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

export function createRenderer<
  HostNode = RendererNode,
  HostElement = RendererElement
>(options: RendererOptions<HostNode, HostElement>) {
   
  return baseCreateRenderer<HostNode, HostElement>(options)
}

该函数接收一个RendererOptions作为参数,其实际是调用了baseCreateRenderer并将options传入

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

function baseCreateRenderer(
    options: RendererOptions,
    createHydrationFns?: typeof createHydrationFunctions
): any {
   
	const {
   
    insert: hostInsert,
    remove: hostRemove,
    patchProp: hostPatchProp,
    forcePatchProp: hostForcePatchProp,
    createElement: hostCreateElement,
    createText: hostCreateText,
    createComment: hostCreateComment,
    setText: hostSetText,
    setElementText: hostSetElementText,
    parentNode: hostParentNode,
    nextSibling: hostNextSibling,
    setScopeId: hostSetScopeId = NOOP,
    cloneNode: hostCloneNode,
    insertStaticContent: hostInsertStaticContent
  } = options
  
    // 声明了许多操作函数,约2000行

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

在调用完baseCreateRenderer后主要返回了三个函数:render,hydratecreateApp

此时renderer便创建完成了。

这其中有一处需要留心,即传入的RendererOptions是什么?为什么在runtime-dom传入,又在runtime-core拆解。

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

const rendererOptions = extend({
    patchProp, forcePatchProp }, nodeOps)
// packages/runtime-dom/src/nodeOps.ts

export const nodeOps: Omit<RendererOptions<Node, Element>, 'patchProp'> = {
   
  insert: (child, parent, anchor) => {
   
    parent.insertBefore(child, anchor || null)
  },

  remove: child => {
   
    const parent = child.parentNode
    if (parent) {
   
      parent.removeChild(child)
    }
  },
	// ...
}

是不是很熟悉,其实就是对于dom操作的封装。那为什么要在runtime-dom中传入,runtime-core拆解?

其实是因为在Vue3中runtime-coreruntime-dom的拆分,runtime-core不应该关心实际的操作,这样当新平台要接入时(比如weex)就可以只实现属于自己平台的nodeOps

总结:创建renderer的函数调用顺序为

  1. ensureRenderer()
  2. createRenderer()
  3. baseCreateRenderer()

创建app

当创建完renderer后返回了3个函数,我们可以看到其中createApp实际上是引用了createAppAPI(render, hydrate),所以其实const app = ensureRenderer().createApp(...args)创建app实例时,调用的是createAppAPI的返回值(运用柯里化,返回的是一个函数)

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

export function createAppContext(): AppContext {
   
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值