Vue3源码解读之runtime(上)
前言
上一篇文章,我们提到packages中核心的源码主要分为三部分,接下来我们就开始阅读runtime部分的代码
createApp(App).mount('#app')
接下来我们就以入口文件中的这行代码开始来一步步深入
初始化
上一篇文章中我们提到vue主入口文件中,引入导出了runtime-dom和compiler,而createApp就是来自runtime-dom
// packages/runtime-dom/src/index.ts
export const createApp = ((...args) => {
const app = ensureRenderer().createApp(...args)
if (__DEV__) {
injectNativeTagCheck(app) // 在dev环境下,注册一个方法isNativeTag,挂载到app.config下面
}
const {
mount } = app
app.mount = (containerOrSelector: Element | ShadowRoot | string): any => {
// ...
}
return app
}) as CreateAppFunction<Element>
在该函数内部中通过调用ensureRenderer()和createApp(...args)创建了app实例并把实例返回出去,因此我们可以在app实例中安装插件,设置全局指令等等。这其中又是怎么实现的呢?
创建renderer
ensureRenderer()函数的用途是什么呢?
// packages/runtime-dom/src/index.ts
function ensureRenderer() {
return renderer || (renderer = createRenderer<Node, Element>(rendererOptions))
}
我们可以看到调用该函数后返回一个renderer,若没有renderer则调用createRenderer来进行创建。
而这边的createRenderer则是来自runtime-core
// packages/runtime-core/src/index.ts
export function createRenderer<
HostNode = RendererNode,
HostElement = RendererElement
>(options: RendererOptions<HostNode, HostElement>) {
return baseCreateRenderer<HostNode, HostElement>(options)
}
该函数接收一个RendererOptions作为参数,其实际是调用了baseCreateRenderer并将options传入
// packages/runtime-core/src/renderer.ts
function baseCreateRenderer(
options: RendererOptions,
createHydrationFns?: typeof createHydrationFunctions
): any {
const {
insert: hostInsert,
remove: hostRemove,
patchProp: hostPatchProp,
forcePatchProp: hostForcePatchProp,
createElement: hostCreateElement,
createText: hostCreateText,
createComment: hostCreateComment,
setText: hostSetText,
setElementText: hostSetElementText,
parentNode: hostParentNode,
nextSibling: hostNextSibling,
setScopeId: hostSetScopeId = NOOP,
cloneNode: hostCloneNode,
insertStaticContent: hostInsertStaticContent
} = options
// 声明了许多操作函数,约2000行
return {
render,
hydrate,
createApp: createAppAPI(render, hydrate)
}
}
在调用完baseCreateRenderer后主要返回了三个函数:render,hydrate,createApp。
此时renderer便创建完成了。
这其中有一处需要留心,即传入的RendererOptions是什么?为什么在runtime-dom传入,又在runtime-core拆解。
// packages/runtime-dom/src/index.ts
const rendererOptions = extend({
patchProp, forcePatchProp }, nodeOps)
// packages/runtime-dom/src/nodeOps.ts
export const nodeOps: Omit<RendererOptions<Node, Element>, 'patchProp'> = {
insert: (child, parent, anchor) => {
parent.insertBefore(child, anchor || null)
},
remove: child => {
const parent = child.parentNode
if (parent) {
parent.removeChild(child)
}
},
// ...
}
是不是很熟悉,其实就是对于dom操作的封装。那为什么要在runtime-dom中传入,runtime-core拆解?
其实是因为在Vue3中runtime-core和runtime-dom的拆分,runtime-core不应该关心实际的操作,这样当新平台要接入时(比如weex)就可以只实现属于自己平台的nodeOps。
总结:创建renderer的函数调用顺序为
ensureRenderer()createRenderer()baseCreateRenderer()
创建app
当创建完renderer后返回了3个函数,我们可以看到其中createApp实际上是引用了createAppAPI(render, hydrate),所以其实const app = ensureRenderer().createApp(...args)创建app实例时,调用的是createAppAPI的返回值(运用柯里化,返回的是一个函数)
// packages/runtime-core/src/apiCreateApp.ts
export function createAppContext(): AppContext {

本文深入解读Vue3的runtime部分,从创建renderer、初始化app到mount过程,详细剖析createVNode和render函数,揭示Vue3在组件创建和渲染中的实现细节。
最低0.47元/天 解锁文章
311

被折叠的 条评论
为什么被折叠?



