【vue3源码学习】初始化流程分析:渲染器与 createApp

学习 vue3 源码,是不是一时不知道从哪里入手?不了解哪些有依赖关系,哪些能做什么事?今天我们就 vue 项目的吃实话流程进行分析。

(一) 整体结构

vue3 的源码中,其根目录只有两个核心的目录: packages 与 scripts。scripts 只要用于一些工程操作,比如检查环境、打包等,而真正的源码都位于 packages 目录下。

  • reactivity : 响应式API,例如toRef、reactive、Effect、computed、watch等,可作为与框架无关的包,独立构建。
  • runtime-core : 平台无关的运行时核心代码。包括虚拟dom渲染、组件实现和JavaScript API。可以使用这个包针对特定平台构建高价运行时(即定制渲染器)。
  • runtime-dom : 针对浏览器的运行时。包括对原生DOM API、属性(attributes)、特性(properties)、事件回调的处理。
  • runtime-test : 用于测试的轻量级运行时。可以在任何JavaScript环境使用,因为它最终只会呈现JavaScript对象形式的渲染树,其可以用来断言正确的渲染输出。另外还提供用于序列化树、触发事件和记录更新期间执行的实际节点操作的实用工具。
  • server-renderer : 服务端渲染相关。
  • compiler-core : 平台无关的编译器核心代码。包括编译器可扩展基础以及与所有平台无关的插件。
  • compiler-dom : 添加了针对浏览器的附加插件的编译器。
  • compiler-sfc : 用于编译Vue单文件组件的低阶工具。
  • compiler-ssr : 为服务端提供优化后的渲染函数的编译器。
  • template-explorer : 用于调试编译器输出的开发者工具。运行nr dev template-explorer命令后打开它的index.html文件,获取基于当前源代码的模板的编译结果。也可以使用在线版本live version
  • shared : 多个包共享的内部工具(特别是运行时包和编译器包所使用的与环境无关的工具)。
  • vue : 用于面向公众的完整构建,其中包含编译器和运行时。

上述包中,剔除服务端渲染、开发调试、测试等相关代码,它们的依赖关系大致时这样的:

在这里插入图片描述

(二)初始化流程分析

我们今天要研究的初始化流程主线包括了实例创建过程(createApp)与挂载过程(app.mount())

这里我们使用上一篇介绍的调试环境中介绍的单步调试方法
【vue3源码学习】如何开始源码学习及调试环境的安装?

通过单步调试方法,我们来分析 createApp 与 mount 的实现。

createApp

从 createApp 出发进入 ensureRenderer() 方法

当使用createApp创建应用实例时,会首先调用一个ensureRenderer方法。

ensureRenderer函数会返回一个渲染器renderer,这个renderer是个全局变量,如果不存在,会使用createRenderer方法进行创建,并将创建好的renderer赋值给这个全局变量。

在源码文件中的路径:packages\runtime-dom\src\index.ts
在这里插入图片描述
而createRenderer函数中会调用baseCreateRenderer函数,并返回其结果。
这个返回值就是渲染器:

return {
   render, //  把接收到的 vnode 转换成 DOM,追加到宿主元素
   hydrate, // SSR ,服务端将 vnode 生成为 html
   createApp: createAppAPI(render, hydrate) // 创建 App 实例
 }

渲染器是什么

由上边的代码可以看出,渲染器就是一个包含 render、hydrate、createApp 的对象。

他的作用就是:

  • 实现首次渲染
  • 获取应用实例

我们可以看到真正初始化的核心方法是 createAppAPI(render, hydrate)

createAppAPI 又返回了一个 createApp 方法,而这个方法才是我们看到的 vue 实例的真实样子。我们平常熟悉的config、use、mixin、mount 等重要的方法都在这里。

在源码文件中的路径:packages\runtime-core\src\apiCreateApp.ts

在这里插入图片描述

敲黑板:此处是重点 我们会发现 vue2 与 vue3 创建实例的方法是有很大不同的:
.
..........................................................................
.
vue2
vue2 的所有 Vue 实例是共享一个 Vue 构造函数对象的,包括全局指令/全局组件,无法做到项目隔离。也就是说整个项目中,只有一个根 Vue 实例,其他的单文件组件创建的 Vue 实例都会成为它的子实例。

import Vue from 'Vue'
import APP from './APP.vue'

const vm = new Vue({
  render:h => h(APP)
})
vm.$mount('#app')

vue3
而 vue3 是通过 createApp 工厂函数来创建实例的,通过createApp方法可以返回一个提供应用上下文的应用实例,不同实例注册的组件无法在不同的实例下使用。

import {createApp} from 'vue'
import APP from './APP.vue'

const app = createApp(APP)
app.mount('#app')

下期预告:

挂载都做了什么?

  • 挂载只执行一次
  • 初始化 => 看到渲染过程
  • 建立更新机制 => 不停循环
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

代码搬运媛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值