createApp
返回一个提供应用上下文的应用实例。应用实例挂载的整个组件树共享同一个上下文。
import { createApp } from 'vue'
const app = createApp({})
你可以在 createApp 之后链式调用其它方法,这些方法可以在应用 API 中找到。
参数
该函数接收两个参数,第一个是根组件选项对象,第二个是将根prop传递给应用程序
从一个栗子开始
const { createApp } = Vue;
createApp({
data() {
return {
title: 'hello, Vue3~'
}
}
}).mount('#demo');
我们看看createApp方法中是如何实现的?
// packages/runtime-dom/src/index.ts
export const createApp = ((...args) => {
const app = ensureRenderer().createApp(...args)
if (__DEV__) {
injectNativeTagCheck(app)
injectCompilerOptionsCheck(app)
}
const { mount } = app
app.mount = (containerOrSelector: Element | ShadowRoot | string): any => {
const container = normalizeContainer(containerOrSelector)
if (!container) return
const component = app._component
if (!isFunction(component) && !component.render && !component.template) {
// __UNSAFE__
// Reason: potential execution of JS expressions in in-DOM template.
// The user must make sure the in-DOM template is trusted. If it's
// rendered by the server, the template should not contain any user data.
component.template = container.innerHTML
// 2.x compat check
if (__COMPAT__ && __DEV__) {
for (let i = 0; i < container.attributes.length; i++) {
const attr = container.attributes[i]
if (attr.name !== 'v-cloak' && /^(v-|:|@)/.test(attr.name)) {
compatUtils.warnDeprecation(
DeprecationTypes.GLOBAL_MOUNT_CONTAINER,
null
)
break
}
}
}
}
// clear content before mounting
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
}) as CreateAppFunction<Element>
createApp方法中的重点在于ensureRenderer
// packages/runtime-dom/src/index.ts
const rendererOptions = extend({ patchProp, forcePatchProp }, nodeOps)
// lazy create the renderer - this makes core renderer logic tree-shakable
// in case the user only imports reactivity utilities from Vue.
let renderer: Renderer<Element> | HydrationRenderer
let enabledHydration = false
function ensureRenderer() {
return renderer || (renderer = createRenderer<Node, Element>(rendererOptions))
}
ensureRenderer方法中调用createRenderer
// packages/runtime-core/src/renderer.ts
export function createRenderer<
HostNode = RendererNode,
HostElement = RendererElement
>(options: RendererOptions<HostNode, HostElement>) {
return baseCreateRenderer<HostNode, HostElement>(options)
}
createRenderer方法中调用了baseCreateRenderer,baseCreateRenderer方法中完成了vnode、diff、patch,方法比较庞大,但最终返回了render、hydrate和createApp3个参数,而createApp正是createApp方法中ensureRenderer()调用的createApp()
// packages/runtime-core/src/renderer.ts
// overload 1: no hydration
function baseCreateRenderer<
HostNode = RendererNode,
HostElement = RendererElement
>(options: RendererOptions<HostNode, HostElement>): Renderer<HostElement>
// overload 2: with hydration
function baseCreateRenderer(
options: RendererOptions<Node, Element>,
createHydrationFns: typeof createHydrationFunctions
): HydrationRenderer
// implementation
function baseCreateRenderer(
options: RendererOptions,
createHydrationFns?: typeof createHydrationFunctions
): any {
// 省略2000行
return {
render,
hydrate,
createApp: createAppAPI(render, hydrate)
}
}
返回的createApp方法调用了createAppAPI,并将生成的render和hydrate作为参数传递进去,createApp首先会对rootProps进行判断,app对象中均是一些眼熟的方法,与现有API调用方法一致
// packages/runtime-core/src/apiCreateApp.ts
export function createAppAPI<HostElement>(
render: RootRenderFunction,
hydrate?: RootHydrateFunction
): CreateAppFunction<HostElement> {
return function createApp(rootComponent, rootProps = null) {
if (rootProps != null && !isObject(rootProps)) {
__DEV__ && warn(`root props passed to app.mount() must be an object.`)
rootProps = null
}
const context = createAppContext()
const installedPlugins = new Set()
let isMounted = false
const app: App = (context.app = {
_uid: uid++,
_component: rootComponent as ConcreteComponent,
_props: rootProps,
_container: null,
_context: context,
version,
get config() {
return context.config
},
set config(v) {
if (__DEV__) {
warn(
`app.config cannot be replaced. Modify individual options instead.`
)
}
},
use() {},
mixin() {},
component() {},
directive() {},
mount() {},
unmount() {},
provide() {}
})
if (__COMPAT__) {
installAppCompatProperties(app, context, render)
}
return app
}
}
createAppContext的实现
// packages/runtime-core/src/apiCreateApp.ts
export function createAppContext(): AppContext {
return {
app: null as any,
config: {
isNativeTag: NO,
performance: false,
globalProperties: {},
optionMergeStrategies: {},
errorHandler: undefined,
warnHandler: undefined,
compilerOptions: {}
},
mixins: [],
components: {},
directives: {},
provides: Object.create(null)
}
}
createAppAPI最终返回app实例对象,createApp整个流程结束