createApp 过程
const app = ensureRenderer().createApp(...args)
ensureRenderer (runtime-dom/index)
return renderer = createRenderer(rendererOptions)
createRenderer (runtime-dom/renderer) 创建渲染器
export function createRenderer(options) {
return baseCreateRenderer(options)
}
function baseCreateRenderer() {
const patch = () => {}
// 挂载组件
const mountComponent = () => {}
// 注册 setup 渲染副作用函数
const setupRenderEffect = () => {}
// render 函数
const render = (vnode, container) => {
if(vnode == null) {
// unmount
unmount()
} else {
// patch 上面的
patch(container._vnode || null, vnode, container)
}
flushPreFlushCbs()
flushPostFlushCbs()
// 更新容器 _vnode
container._vnode = vnode
}
return {
render,
hydrate,
createApp: createAppAPI(render, hydrate)
}
}
createAppAPI (runtime-core/apiCreateApp)
return function createApp(rootComponnet, rootProps = null) {
if(!isFunction(rootComponent)) { rootComponent = { ...rootComponent } }
if(rootProps != null && !isObject(rootProps)) { rootProps = null }
// 创建上下文
const context = createAppContext()
// 插件
const installedPlugins = new Set()
let isMounted = false
const app = {
version,
get config() {
return context.config
},
set config() {},
use() {},
mixin() {},
component() {},
directive() {},
mount() {},
unmount() {},
provide() {},
}
return app
}
传入根组件
rootComponent
,既调用createApp
传入的App
组件const app = createApp(App)
判断传入的
rootComponent
是否是函数,不是则展开判断传入的
rootProps
进行验证是否是 obj创建上下文
const context = createAppContext()
安装插件存放
const installedPlugins = new Set()
创建 app 实例,包括
config
use
version
mixin
component
directive
mount
unmount
provide
等config :返回上下文的配置
jsconfig: { isNativeTag: NO, performance: false, globalProperties: {}, optionMergeStrategies: {}, errorHandler: undefined, warnHandler: undefined, compilerOptions: {} },
use :
new Set()
数据结构类型,如果存在报警告;如果存在 install 方法,且是函数,添加插件,调用install 方法;如果插件是函数,直接执行mixin :数组结构,判断是否 includes,直接 push
component :
context.components[name] = component
directive :
context.directives[name] = directive
mount :
createVNode()
函数返回 vnode;render(vnode, rootContainer)
进行渲染;isMounted 设为 true;app._container = rootContainer
将根容器缓存;安装 devtoolunmount :
render(null, app._container)
;卸载 devtoolprovide :
context.provides[key] = value
render (runtime-dom/renderer) => patch()
内部首次执行 patch
函数
const patch = (
n1, // 旧
n2, // 新
container // 容器
) => {}
n1 n2 一样,直接返回
n1 n2 不是相同的类型,直接卸载旧的树 n1
判断 n2 的 type 类型,通过
switch case
逐步执行。Text
Comment
Static
Fragment
;ELEMENT
COMPONENT
TELEPORT
SUSPENSE
;设置 ref 属性setRef(ref, n1 && n1.ref, ...)
processText
processCommentNode
mountStaticNode patchStaticNode
processFragment
processElement
processComponent
type.process (TELEPORT | SUSPENSE)
setRef
patch(n1, n2, container)
processComponent(n1, n2, container) 组件
- 判断 如果
n1 == null
,挂载过程。如果存在 keepalive,调用 parentComponent.ctx.activate 将组件设置为活跃状态;否则执行 挂载组件mountComponent
- n1 不为 null,执行 组件更新
updateComponent
mountComponent(initialVNode, container) ()
- 创建组件实例 instance
- 注册 HMR 热更新
- 异常上下文注册,开始计时 mount
startMeause(instance, 'mount')
- 判断 isKeepAlive
- 开始计时 init
startMeause(instance, 'init')
,创建组件setupComponent(instance)
,结束计时 initendMeause(instance, 'init')
setupRenderEffect()
注册渲染副作用函数- 移除异常上下文
popWarningContext()
;结束计时 mountendMeause(instance, 'mount')
setupComponent(instance)
export function setupComponent(instance) {
const { props, children } = instance.vnode
const isStateful = isStatefulComponent(instance)
// 初始化 props slots
initProps(instance, props) // 内部使用 shallowReactive 进行浅响应
initSlots(instance, children)
const setupResult = isStateful ? setupStatefulComponent(instance) : undefined
return setupResult
}
- 从组件实例上解构 props children
- 判断是否为状态组件
- 获取到组件状态 setup 函数的返回结果
setupStatefulComponent
function setupStatefulComponent(instance) {
const Component = instance.type
instance.accessCache = Object.create(null)
instance.proxy = markRaw(new Proxy(instance.ctx, PublicInstanceProxyHandlers))
}
handleSetupResult
function handleSetupResult(instance, setupResult) {
if(isFunction(setupResult)) {
instance.render = setupResult
}
else if(isObject(setupResult)) {
instance.setupState = proxyRefs(setupResult)
}
finishComponentSetup(instance)
}
- 如果 setupResult 是函数,即为 render 函数,
instance.render = setupResult
- 如果是 Obj,则为响应式状态数据和方法等,经过
proxyRefs
处理,然后赋值给 组件实例的 setupStateinstance.setupState = proxyRefs(setupResult)
- 调用
finishComponentSetup(instance)
finishComponentSetup 编译器注入 compile
function finishComponentSetup(instance) {
const Component = instance.type
if(!instance.render) {
// 编译器存在
if(compile && !Component.render) {
// 模版
const template = Component.template
if(template) {
// compile 编译器 传入模版,编译器配置项
Component.render = compile(template, finalCompilerOptions)
}
}
}
instance.render = Component.render || () => {}
}
- 获取模版 template,如果模版存在则进行编译,编译计时开始
- 配置编译器配置项
finalCompilerOptions
,使用编译器compile
进行编译 - 赋值给
Component.render
- 编译计时结束
- 然后赋值给组件实例的render
instance.render
registerRuntimeCompiler 注册编译器 (runtime-core/component)
let compile
export function registerRuntimeCompiler(_compile) {
compile = _compile
}
使用此函数注入编译器,在 packages/vue/src/index.ts