1.monorepo的风格进行代码管理
看个例子
首先我们先看v2的代码仓库的目录结构
compiler = > 模板编译相关的代码
core = > 平台无关的运行时代码
platforms = > 平台代码(也是比较核心的内容)
server = > 服务端渲染相关的代码
sfc = > vue文件的解析相关工作及代码
shared = > 共享的工具代码
从上面的这些我们不难看出,他分类了,但是相对于vue3分类的没有那么细分
然后我们看看v3的目录结构
肉眼可见的他的文件夹分类更加的细致以及语义化
比如compiler就对于不同的情况进行了代码的二次归类,并且每个package都有各自的API,
类型等等,这样更好的划分了功能区块,方便维护的时候进行查找,更改,并且可以单独引用其
中的一些功能模块而不需要引入vue.js,极大程度的减少了打包后的体积,这个是在vue2的时
候没办法做到的(比如说只引入vue的响应式模块,而不需要全量引入整个vue)
2.使用了typescript重新对类型进行了编写,增加了项目的可维护性
v2使用了flow 对类型进行支持(但是flow烂尾了,并且很多类型支持的也不是很好,所以
v3重新使用了typescript进行了类型定义)
3.使用了tree-shaking进行打包
通过编译阶段的静态分析,找到没有引入的模块并且打上标注(然后就会在打完包利用插件删
除这一块的内容,比如说 你没有用到keepalive这个组件,那他们对应的代码 就不会打包,
从而减少了打包之后的体积)从而也移除了一些没有使用过的包
4.数据劫持进行了优化(数据双向绑定)
1.渲染的时候使用了数据,对于这一个数据进行劫持,然后内部建立依赖关系(vnode)从而就知道对樱的dom是哪一块
2.v2使用了object.defineProperty这个api,这个api有一定的缺陷,例如必须得知道对
象的key才可以进行劫持,对于多层级对象的监听也相对而言没有那么友好
3.v3使用了proxy进行劫持,劫持了整个对象,也就是对象的新增 删除 等等一系列的全都
触发get set 但是他也有问题 对于层级过深的对象 他也无法监听的到,所以v3在get中
递归的去做响应式处理(这样做有个好处,就是你用到了这一层级的数据,才会去劫持,如果
没有用上 就不会去劫持,这样也可以提高性能)
5.编译优化
vue的编译大概是这么一个流程
new Vue(v3是createApp) --> init --> $mount --> compile --> render --> vnode --> patch -->dom
v3主要是在patch这个阶段进行了优化
优化的例子
<template>
<div id="xxx">
<div>
<span>姓名</span>
<span>{{name}}</span>
</div>
<div>
<span>公司</span>
<span>xxxxx</span>
</div>
<div>
<span>公司地址</span>
<span>xxxxx</span>
</div>
</div>
</template>
` 首先我们先看到这样一段模板,它有很多的静态节点的内容是可以不参与编译,但是v2的watcher是组件级别的会以此遍历整个组件内部的vnode,所以它的编译应该是这样
diff div => diff props(id="xxx")=>diff child(div)=> diff span => diff props(span) => diff child span => end
这里面有大量的静态节点是不需要反复被编译的,动态节点越少,静态节点越多,性能浪费的也越严重然后v3就做了个事儿
首先,他会分析模板 生成一个静态树(将基于动态节点指令分割出来的嵌套部分,每个部分的节点结构是固定的,所以每一个部分只需要一个array来追踪自身包含的静态节点)
利用这个静态树v3把vnode的更新性能和模板整体的大小相关变成了只和动态内容相关从而静态节点就不参与后续的变化了从而节省了大量的性能 `
6.对slot的编译 事件监听 函数的缓存进行了优化 并且修改了diff算法
后续对于slot的源码解读的时候我会详细说这一块的内容
7.新的composition API 语法(对于tree-shaking 更友好 代码也容易压缩)
8.去掉了mixin (解决了mixin来源以及命名的问题,但是可以通过两个文件引入同一个ref后的数据来实现类似于mixin的功能)