app.mount时vue做了些什么
首先创建一个App
import { createApp } from 'vue';
import App from './App.vue';
const app = createApp(App);这个 createApp 是由 createAppAPI 返回的高阶函数:
function createAppAPI<HostElement>(
  render: RootRenderFunction,
  hydrate?: RootHydrateFunction
): CreateAppFunction<HostElement> {
	return function createApp(rootComponent, rootProps = null) {...}
}render 是渲染实现,vue 默认使用 @vue/runtime-dom 中浏览器的渲染实现
Note
从这里可以看出,vue3 分离了渲染器,这也让其拥有了作为跨平台框架的能力
createApp 最后会返回一个 Vue 实例,我们将会调用其 mount 方法渲染到指定元素上
app.mount('#app');在 mount 中,先创建 vnode 节点
const vnode = createVNode(
	rootComponent as ConcreteComponent,
	rootProps
)创建 vnode 节点后,就是渲染
render(vnode, rootContainer, isSVG)render 就是官方的浏览器渲染实现,其内部实现如下
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)
	}
	flushPostFlushCbs()
	container._vnode = vnode
}- 如果节点为 
null,则将节点从当前容器 dom 上卸载 - 否则就进行 
patch(打补丁) - 最后执行 
Post队列中的任务 
Post 队列
watchEffect中的flush会指定响应依赖的执行时机,Post队列中的任务需要在选然后执行
关键就是这里的 patch,在这里面会判断 vnode 的类型
switch (type) {
	case Text:
		...
		break
	case Comment:
		...
		break
	case Static:
		...
		break
	case Fragment:
		...
		break
	default:
		...由于我们还只是抽象的组件,还未渲染,这里会走到 default 中,在这里面判断我们传入的是组件后,会调用 processComponent 方法:
if (shapeFlag & ShapeFlags.ELEMENT) {
	...
} else if (shapeFlag & ShapeFlags.COMPONENT) {
	processComponent(...)
} else {
	...
}接着在里面判断是初次渲染后,会接着调用 mountComponent 方法,在里面创建组件实例
const instance: ComponentInternalInstance =
	compatMountInstance ||
	(initialVNode.component = createComponentInstance(
		initialVNode,
		parentComponent,
		parentSuspense
	))在 mountComponent 中会调用 setupComponent 方法,该方法中进行了很多初始化操作
- 初始化 
props - 初始化插槽
 - 执行 
setup函数 - 根据 
setup返回值或者模板属性,编译render渲染函数 
执行完 setupComponent 后,走到接收该实例的 setupRenderEffect 方法
里面定义了组件渲染、更新的方法 componentUpdateFn,该方法由两百多行,非常的重要,Vue 使用该方法在这里新建了一个响应式副作用,双向绑定的魔法在此展开
// create reactive effect for rendering
const effect = (instance.effect = new ReactiveEffect(
	componentUpdateFn,
	() => queueJob(update),
	instance.scope // track it in component's effect scope
))
const update: SchedulerJob = (instance.update = () => effect.run())
update.id = instance.uid
update() // 执行渲染,渲染过程中使用的响应式变量都会被计入依赖在 componentUpdateFn 中,如果我们是首次渲染,则会调用 renderComponentRoot 构建 vnode 树
const subTree = (instance.subTree = renderComponentRoot(instance))然后执行 patch 将 vnode 渲染到浏览器中,完成首次渲染