Vue3.0
Vue3和Vue2的区别
一.源码组织方式的改变
1.代码全部用Typescript重写
2.使用Monorepo的方式来管理源代码,使用一个项目来管理不同的包,把不同功能的代码放到不同的package中管理。这样的话每个功能模块划分都很明确,模块之间的依赖关系也很明确,并且每个功能模块都能单独发布测试和使用.
二.性能提升
1.响应式系统的升级
Vue2响应式系统
在数据初始化的时候会遍历data中的所有的成员通过defineProperty把对象的属性转化为getter和setter,如果对象的属性又是对象的话需要递归处理每一个子对象.
问题:
- 因为是在初始化进行,即便是不需要使用的对象也进行了响应式处理,浪费了性能
- 虽然Object.defineProperty()是可以对数组实现监听操作的,但是vue并没有实现这个功能,因为数组长度不定而且数据可能会很多,如果对每一个数据都实现监听,性能代价太大
- Object.defineProperty()针对的是对象的某个属性,而且这个操作在vue的初始化阶段就完成了,所以新增的属性无法监听
Vue3响应式系统
Vue3中使用Proxy对象重写了响应式系统,提升了响应式系统的性能和功能.
- 可以监听动态新增的属性
- 可以监听删除的属性
- 可以监听数组的索引和length的属性
所以不需要在初始化去递归处理每一个属性,另外如果有多个属性嵌套的话,只有访问某个属性的时候才会递归处理下一级的属性.
2.编译优化
-静态节点:<div>12<div>
,内容是固定的
-动态节点:<div :id='id'>{{count}}</div>
,内容是动态获取的
Vue2
在Vue2中,重新的渲染的时候会重新去创建新旧Vnode,diff的时候会跳过静态根节点,对比剩下的每一个vnode,哪怕这些节点什么都没做
Vue3
标记和提升所有的静态节点,diff的时候只需要对比动态节点内容
- Fragments(升级vetur插件)
- 静态提升
- Patch flag
- 缓存事件处理函数
https://vue-next-template-explorer.netlify.app/
options勾选上hoistStatic
import { createElementVNode as _createElementVNode, toDisplayString as _toDisplayString, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"
//-- 静态节点提升 start --
const _hoisted_1 = /*#__PURE__*/_createElementVNode("div", null, "静态节点", -1 /* HOISTED */)
const _hoisted_2 = ["id"]
const _hoisted_3 = ["onClick"]
//-- 静态节点提升 end --
export function render(_ctx, _cache, $props, $setup, $data, $options) {
//没有根节点元素会传入 _Fragment,也就是自动帮我们创建一个根节点元素
return (_openBlock(), _createElementBlock(_Fragment, null, [
_hoisted_1,
_createElementVNode("div", null, _toDisplayString(_ctx.count), 1 /* TEXT */),
_createElementVNode("div", { id: _ctx.id }, "id", 8 /* PROPS */, _hoisted_2),
_createElementVNode("button", { onClick: _ctx.dot }, "button", 8 /* PROPS */, _hoisted_3)
], 64 /* STABLE_FRAGMENT */))
}
/ **
例一: _createElementVNode("div", null, _toDisplayString(_ctx.count), 1 /* TEXT */)
创建一个虚拟节点,标签类型为div,属性空,内容动态渲染, 1 是patch flag,代表文本内容是动态绑定的
例二: _createElementVNode("div", { id: _ctx.id }, "id", 8 /* PROPS */, _hoisted_2)
创建一个虚拟节点,标签类型为div,属性id动态渲染, 文本内容id, 8 是patch flag,代表属性是动态绑定的,_hoisted_2其实就是 ["id"],说明动态绑定的是哪些属性
将来在diff的时候,会检测整个block里面带patch flag的标记的节点,静态节点会直接跳过.而且在比较动态节点的时候,会根据patch flag的值去进行比较,如例二中的 8 /* PROPS */, ["id"] ,那么它只会比较这个节点中,属性id的值,降低了性能损耗
**/
我们再去勾选上otions的cacheHandlers,对比变化的代码,
没有事件缓存的:
const _hoisted_3 = ["onClick"]
_createElementVNode("button", { onClick: _ctx.dot }, "button", 8 /* PROPS */, _hoisted_3)
事件缓存的:
_createElementVNode("button", {
onClick: _cache[0] || (_cache[0] = (...args) => (_ctx.dot && _ctx.dot(...args)))
}, "button")
//没有开启缓存,绑定事件行为会被认为是动态绑定,每次都去追踪变化;开启缓存后,下次diff直接使用,不追踪变化
三.优化打包体积
- Vue3.0中移除了一些不常用的API
- 例如:inline-template,filter等
- Tree-shaking
- Vue3中内置的组件和指令以及一些新增的API都是按需引入的,如果你没有使用就不会被打包进去
Vite
Vite vs Vue-CLI
- Vite在开发模式下不需要打包可以直接运行
- 使用浏览器原生支持的ES Module加载模块也就是通过import来导入模块,浏览器通过
<script type='module'>
加载模块代码 - Vue会开启一个测试服务器,会拦截浏览器发起的请求,浏览器会发起请求获取相应的模块,Vite会对浏览器不识别的模块进行处理,例如请求.vue结尾的文件的时候,会在服务器上对文件进行编译,把编译的结果返回给浏览器.
- 使用浏览器原生支持的ES Module加载模块也就是通过import来导入模块,浏览器通过
- Vue-CLI开发模式下必须要对项目打包才可以运行
Vite特点
1.快速冷启动
因为不需要打包,所以可以快速冷启动
2.按需编译
代码是按需编译的,因此只有当代码在当前需要加载的时候才会编译,你不需要在开启开发服务器的时候等待项目被打包,当项目比较大的时候会更明显
3.模块热更新
vite支持模块热更新,并且模块热更新的性能与模块总数无关,无论你有多少模块,html的速度始终很快