CreateApp 作为 vue 的启动函数,返回一个应用实例
一个实例:
const HelloVueApp = { data() { return { message: 'Hello Vue!' } } } Vue.createApp(HelloVueApp).mount('#hello-vue')
export const createApp = ((...args) => {
const app = ensureRenderer().createApp(...args)
if (__DEV__) {
injectNativeTagCheck(app)
injectCustomElementCheck(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) {
component.template = container.innerHTML
}
// 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>
这一段代码点有两个,
const app = ensureRenderer().createApp(...args)
还有一个是改写mount;app.mount=......
const { mount } = app
先说改写mount,是因为在不同平台上mount所做的工作不一样;
mount 在createSSRApp 和createApp中适配不同的环境;
再说说ensureRenderer()做了什么;
function ensureRenderer() {
return renderer || (renderer = createRenderer<Node, Element>(rendererOptions))
}
createRenderer
export function createRenderer<
HostNode = RendererNode,
HostElement = RendererElement
>(options: RendererOptions<HostNode, HostElement>) {
return baseCreateRenderer<HostNode, HostElement>(options)
}
baseCreateRenderer
baseCreateRenderer本质是一个非常复杂的函数,包含了vnode,mount等等;
最后返回了:
return {
render,
hydrate,
createApp: createAppAPI(render, hydrate)
}
我们回头看:const app = ensureRenderer().createApp(...args)
其实就是调用了baseCreateRenderer的createApp
所以:本质上就是调用createAppAPI 这个函数返回什么呢,一个app对象;
app对象里面包含了mount方法:
mount(
rootContainer: HostElement,
isHydrate?: boolean,
isSVG?: boolean
): any {
if (!isMounted) {
const vnode = createVNode(
rootComponent as ConcreteComponent,
rootProps
)
// store app context on the root VNode.
// this will be set on the root instance on initial mount.
vnode.appContext = context
// HMR root reload
if (__DEV__) {
context.reload = () => {
render(cloneVNode(vnode), rootContainer, isSVG)
}
}
if (isHydrate && hydrate) {
hydrate(vnode as VNode<Node, Element>, rootContainer as any)
} else {
render(vnode, rootContainer, isSVG)
}
isMounted = true
app._container = rootContainer
// for devtools and telemetry
;(rootContainer as any).__vue_app__ = app
if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
devtoolsInitApp(app, version)
}
return vnode.component!.proxy
} else if (__DEV__) {
warn(
`App has already been mounted.\n` +
`If you want to remount the same app, move your app creation logic ` +
`into a factory function and create fresh app instances for each ` +
`mount - e.g. \`const createMyApp = () => createApp(App)\``
)
}
}
createAppAPI中的mount函数被作为一个公共部分抽离出来放在该写的mount函数中;