Vue3源码解析之createApp方法

Posted 闹闹前端

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue3源码解析之createApp方法相关的知识,希望对你有一定的参考价值。

运行vue3源码

  • clone 仓库到本地

git clone https://github.com/vuejs/vue-next.git
  • 进入目录

cd vue-next
  • 安装依赖

yarn
  • 打包项目

yarn build vue -f global

运行完后,在package/vue/dist/目录下就会有打包完成后的文件vue.global.js

  • 使用

html文件中引用vue.global.js文件即可

入口文件

packages/vue/src/index.ts开始

在文件的第45行代码:

export * from '@vue/runtime-dom';

根据此行代码我们进入到runtime-dom/index.ts文件

文件第20行到56行代码如下:

export const createApp = (): App<Element> => {
const app = baseCreateApp()

if (__DEV__) {
// Inject `isNativeTag`
// this is used for component name validation (dev only)
Object.defineProperty(app.config, 'isNativeTag', {
value: (tag: string) => isHTMLTag(tag) || isSVGTag(tag),
writable: false
})
}

const mount = app.mount
app.mount = (component, container, props): any => {
if (isString(container)) {
container = document.querySelector(container)!
if (!container) {
__DEV__ &&
warn(`Failed to mount app: mount target selector returned null.`)
return
}
}
if (
__RUNTIME_COMPILE__ &&
!isFunction(component) &&
!component.render &&
!component.template
) {
component.template = container.innerHTML
}
// clear content before mounting
container.innerHTML = ''
return mount(component, container, props)
}

return app
}

这便是函数createApp定义的地方

由此我们知道createApp函数是由

const app = baseCreateApp()

执行后返回一个app对象,app对象上有mount方法,createApp函数内部,使用装饰器模式对mount方法进行装饰,最后仍返回app对象

而且我们也可以知道mount方法有三个参数:

  • coumponent

  • container

  • props(可选)

因此我们就能明白了Vue3Vue2入口的区别

Vue2的入口代码如下:

app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}

})

Vue3的入口代码如下:

const MyConponent = {
data: {
message: 'Hello Vue!'
}

}
let app = Vue.createApp();
app.mount(MyConponent, '#app');

baseCreateApp

我们继续看文件packages/runtime-dom/src/index.ts 第12行代码如下:

const { render: baseRender, createApp: baseCreateApp } = createRenderer({
patchProp,
...nodeOps
})

这是利用对象的解构,把createRenderer执行结果中的createApp赋值给baseCreateApp

找到createRenderer函数的导入文件是packages/runtime-core/src/renderer.ts

在文件第165行代码是函数createRenderer的定义,我们简化一下代码

export function createRenderer(
options: RendererOptions<HostNode, HostElement>
)
{
// 此处省略代码......
return {
render,
createApp: createAppAPI(render)
}
}

能看出它返回了一个包含了rendercreateApp对象。

createAppAPI

在文件package/runtime-core/src/renderer.ts文件的第48行找到createAppAPI的导入文件

import { App, createAppAPI } from './apiApp'

进入文件,此文件内容比较简单,定义了很多自定义类型和接口

看一下createAppAPI的定义函数,我对函数进行精简,把DEV环境的代码删除

export function createAppAPI<HostNode, HostElement>(
render: RootRenderFunction<HostNode, HostElement>
): () => App<HostElement> {
return function createApp(): App {
const context = createAppContext()
const installedPlugins = new Set()

let isMounted = false

const app: App = {
get config() {
return context.config
},

set config(v) {

},

use(plugin: Plugin) {
if (installedPlugins.has(plugin)) {

} else if (isFunction(plugin)) {
installedPlugins.add(plugin)
plugin(app)
} else if (plugin && isFunction(plugin.install)) {
installedPlugins.add(plugin)
plugin.install(app)
}
return app
},

mixin(mixin: ComponentOptions) {

if (!context.mixins.includes(mixin)) {
context.mixins.push(mixin)
}

return app
},

component(name: string, component?: Component): any {
if (!component) {
return context.components[name]
}
context.components[name] = component
return app
},

directive(name: string, directive?: Directive) {
if (!directive) {
return context.directives[name] as any
}
context.directives[name] = directive
return app
},

mount(
rootComponent: Component,
rootContainer: HostElement,
rootProps?: Data
): any {
if (!isMounted) {
const vnode = createVNode(rootComponent, rootProps)

vnode.appContext = context
render(vnode, rootContainer)
isMounted = true
return vnode.component!.renderProxy
}
},

provide(key, value) {

context.provides[key as string] = value

return app
}
}

return app
}
}

很容易就能知道,此函数是一个高阶函数, 最终返回了createApp函数,而createApp最终返回了app

app对象上有configusemixincomponentdirectivemountprovide

至此我们便清楚了入口文件createApp函数执行的内部流程


以上是关于Vue3源码解析之createApp方法的主要内容,如果未能解决你的问题,请参考以下文章

Vue3 源码逐行解析

createApp().mount('#app') 清除vue3中#app的子元素

极品vue3,你必须学会的东西

Vue3实现列表循环

Vue3 源码解析:代码生成器

vue3在install中mount得不到实例