Vue3优化点
源码优化
使用monorepo和TS管理和开发源码,提升自身代码可维护性 monorepo把模块拆分到不同的package中,每个package有各自的APi、类型定义和测试。模块拆分更细化,职责划分更明确,模块之间的依赖关系更明确。
vue2中使用的是flow,但是flow对于复杂数据类型的检测不友好,不能检测到propOptions的类型
性能优化
引入treee-shaking的技术,依赖ES6模块语法的静态结构(import /export),通过编译阶段的静态分析,找到没有引入的模块并打上标记。
项目中没有引入的组件,打包后就不会引入组件,间接减少项目的体积
数据劫持优化
object.defineProperty劫持数据的getter和setter,但这个API有缺陷,必须知道要拦截的Key是什么,不能检测对象的添加和删除,虽然vue中提供了delete实力方法。
对于嵌套层级比较深的对象,需要递归遍历对象,把每一层的数据都变成响应式的,增加了性能负担
Proxy API做数据劫持,getter和setter方法,是劫持整个对象,对对象的增加和删除都能检测到。
注意:proxy API 并不能监听到内部深层次的对象变化,vue3中处理方式是在getter中去递归响应式。【好处是:只有在真正访问到的内部对象才会变成响应式】
编译优化--- diff
通过编译阶段对静态模版的分析,编译生成Block tree
Block tree是将一个模版基于动态节点指令切割的嵌套区块,每个区块内部的节点结构是固定的,每个区块只需要一个Array追踪自身包含的动态节点。
借助Block tree,vue.js将vnode更新性能由与模版整体大小相关提升为与动态内容的数量相关
编译阶段还包含了对slot的编译优化,事件监听函数的缓存优化,运行时重写了diff算法
语法优化--composition API
options API是按照methods\computed\data\props不同的选项分类的。在大型组件中,一个组件会有很多个处理逻辑点,不友好
composition API 需要修改的都在一个函数中,方便
优化逻辑复用
vue2中mixins,会出现命名冲突和数据来源不清晰的情况
mixins会定义props、data时会出现相同的变量,导致命名冲突
composition API 在逻辑复用有优势,也提供类型支持。在调用函数时,所有的类型被推导出来,不会像o ptions API,使用this
vnode到真实的DOM渲染过程
创建vnode----渲染vnode---生成DOM
入口文件
createApp:
const createApp = ((...args)=>{
// 创建app对象
const app = ensureRenderer().createApp(...args)
const {mount} = app
// 重写mount方法
app.mount = (containerOrSelector) => {
...
}
return app
})
ensureRender()用来创建一个渲染器对象:
源码核心模块
Vue.js 的核心思想可以概括为以下几点:
- 响应式数据绑定:Vue.js 通过数据劫持和依赖追踪技术,实现了数据的双向绑定,使得数据和视图之间能够保持实时同步。
- 组件化构建:Vue.js 采用组件化思想,将页面拆分为多个独立的组件,提高了代码的可维护性和复用性。
- 虚拟 DOM:Vue.js 通过虚拟 DOM 技术,减少了对真实 DOM 的操作,提高了页面的渲染性能。
所有的目录中最核心的就是packages 目录 , Vue3 的源码存放在此目录中:
- compiler-core: 编译解析核心,与具体环境无关,主要生成AST, 并根据AST生成render()方法
- compiler-dom: 浏览器环境中模板解析逻辑, 如处理HTML转义, 处理v-model等指令
- compiler-sfc: 负责解析Vue单文件组件
- compiler-ssr: 服务端渲染环境中的模板解析逻辑
- reactivity: 响应式数据相关逻辑,Proxy 就在这里面
- runtime-core: 运行时与创建实例相关代码
- runtime-dom: 浏览器环境中的运行时核心
- runtime-test: 内部测试代码
- server-renderer: 用于SSR服务端渲染的逻辑
- shared: Vue3 工具库,一些通用方法
- size-check: 用于测试tree shaking 后代码大小的示例库
- template-explorer: 用于检查模板编译后的输出, 主要用于开发调试
- vue: Vue3 主入口文件,包括运行时和 编译器
最重要源码模块
通过目录名称我们可以看到package中最重要的模块有5个, 分别为
- compiler-core :编译
- compiler-dom
- runtime-core:运行
- runtime-dome
- reactivity:响应式