一、入口函数
第一步:创建
app
实例,调用
ensureRenderer()
方法,在这个方法中判断了是否有
render
渲染器,如果没有的话调用
createRenderer<Node, Element | ShadowRoot>(rendererOptions))
方法创建
function ensureRenderer() {
return (
renderer ||
(renderer = createRenderer<Node, Element | ShadowRoot>(rendererOptions))
)
}
在
createRenderer
方法中调用
baseCreateRenderer
方法
export function createRenderer<
HostNode = RendererNode,
HostElement = RendererElement
>(options: RendererOptions<HostNode, HostElement>) {
return baseCreateRenderer<HostNode, HostElement>(options)
}
baseCreateRenderer
方法是这里最核心的方法,这段代码有两千多行,只解读核心部分,调用了
createAppAPI
,返回实力的方法,例如: mount mixin provide 等方法
function baseCreateRenderer(
options: RendererOptions,
createHydrationFns?: typeof createHydrationFunctions
): any {
/**
**
**
**
*/
const render: RootRenderFunction = (vnode, container, isSVG) => {
if (vnode == null) {
if (container._vnode) {
unmount(container._vnode, null, null, true)
}
} else {
patch(container._vnode || null, vnode, container, null, null, null, isSVG)
}
flushPreFlushCbs()
flushPostFlushCbs()
container._vnode = vnode
}
let hydrate: ReturnType<typeof createHydrationFunctions>[0] | undefined
return {
render,
hydrate,
createApp: createAppAPI(render, hydrate)
}
}
createAppAPI
方法返回的实例:
export function createAppAPI<HostElement>(
render: RootRenderFunction<HostElement>,
hydrate?: RootHydrateFunction
): CreateAppFunction<HostElement> {
return function createApp(rootComponent, rootProps = null) {
if (!isFunction(rootComponent)) {
rootComponent = { ...rootComponent }
}
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,
_instance: null,
version,
get config() {
return context.config
},
set config(v) {
if (__DEV__) {
warn(
`app.config cannot be replaced. Modify individual options instead.`
)
}
},
use(plugin: Plugin, ...options: any[]) {
return app
},
mixin(mixin: ComponentOptions) {
return app
},
component(name: string, component?: Component): any {
return app
},
directive(name: string, directive?: Directive) {
return app
},
mount {
},
unmount() {
},
provide(key, value) {
return app
}
})
if (__COMPAT__) {
installAppCompatProperties(app, context, render)
}
return app
}
}
第二步:调用
ensureRenderer
里返回的
createApp
方法,最终返回一系列方法,实例化给
app
第三步:重写
mount
方法
第四步:清空容器,在重写的
mount
方法中去创建
proxy
实例,最终返回的是一个
vnode
export const createApp = ((...args) => {
// 创建了 render 渲染器,和创建了 app 实例,最终返回 app 应用实例 createAppAPI 的方法包括 mount mixin provide 等方法
const app = ensureRenderer().createApp(...args)
if (__DEV__) {
injectNativeTagCheck(app)
injectCompilerOptionsCheck(app)
}
const { mount } = app
// 重写 app 的 mount 方法
app.mount = (containerOrSelector: Element | ShadowRoot | string): any => {
// 返回 containerOrSelector 对应的容器
const container = normalizeContainer(containerOrSelector)
if (!container) return
const component = app._component
// 组件不存在render函数和模板template,则使用container的innerHTML做为组件模板
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', '')
}
// 返回的是个 vnode
return proxy
}
return app
}) as CreateAppFunction<Element>