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(可选)
因此我们就能明白了Vue3和Vue2入口的区别
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)
}
}
能看出它返回了一个包含了render和createApp对象。
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对象上有config、use、mixin、component、directive、mount、provide。
至此我们便清楚了入口文件createApp函数执行的内部流程
以上是关于Vue3源码解析之createApp方法的主要内容,如果未能解决你的问题,请参考以下文章