Vue.js 3.0介绍

173 阅读3分钟

内容输出来源:拉勾教育大前端高薪训练营

一、Vue.js源码组织方式

1.源码采用TypeScript重写

提高了代码的可维护性。大型项目的开发都推荐使用类型化的语言,在编码的过程中检查类型的问题。

2.使用Monorepo管理项目结构

使用一个项目管理多个包,把不同功能的代码放到不同的package中管理,每个功能模块都可以单独发布,单独测试,单独使用。
packages目录结构:

└── packages/
    ├── compiler-core # 和平台无关的编译器
    ├── compiler-dom # 浏览器平台下的编译器,依赖于compiler-core
    ├── compiler-sfc # 单文件组件编译器,依赖于compiler-core和compiler-dom
    ├── compiler-ssr # 服务端渲染的编译器,依赖于compiler-dom
    ├── reactivity # 数据响应式系统
    ├── runtime-core # 和平台无关的运行时
    ├── runtime-dom # 针对浏览器的运行时,处理原生dom的api、事件等
    ├── runtime-test # 专门为测试而编写的轻量级运行时,渲染出来的dom树其实是一个js对象,可以运行在所有支持js的环境里
    ├── server-renderer # 用于服务端渲染
    ├── shared # 内部使用的公共的api
    ├── size-check # 私有不会发布到npm,作用是在tree shaking之后检查包的大小
    ├── template-explorer # 在浏览器运行的实时编译组件会输出render函数
    └── vue # 构建完整版的vue依赖于compiler和runtime
    └── global.d.ts

3.不同构建版本

Vue3中不再构建UMD模块化的方式,因为UMD会让代码有更多冗余,它要支持多种模块化的方式。Vue3中将CJS、ESModule和自执行函数的方式分别打包到了不同的文件中。在packages/vue/dist中有Vue3的不同构建版本。

  • cjs(两个版本都是完整版本,包含编译器)
    • vue.cjs.js
    • vue.cjs.prod.js(生产版本,代码进行了压缩)
  • global(这四个版本都可以在浏览器中直接通过scripts标签导入,导入之后会增加一个全局的Vue对象)
    • vue.global.js(完整版,包含编译器和运行时)
    • vue.global.prod.js(完整版,包含编译器和运行时,生产版本,代码进行了压缩)
    • vue.runtime.global.js(只包含运行时)
    • vue.runtime.global.prod.js(只包含运行时,生产版本,代码进行了压缩)
  • browser(四个版本都包含esm,浏览器的原生模块化方式,可以直接通过<script type="module" />的方式导入模块)
    • vue.esm-browser.js
    • vue.esm-browser.prod.js
    • vue.runtime.esm-browser.js
    • vue.runtime.esm-browser.prod.js
  • bundler(这两个版本没有打包所有代码,只会打包使用的代码,需要配合打包工具来使用,会让Vue体积更小)
    • vue.esm-bundle.js
    • vue.runtime.esm-bundler.js

二、Composition API

1.学习Composition API的资源:

2.设计动机

  • Options API
    • 包含一个描述组件选项(data、methods、props等)的对象
    • Options API 开发复杂组件,同一个功能逻辑的代码被拆分到不同选项
  • Composition API
    • Vue.js 3.0新增的一组API
    • 一组基于函数的API
    • 可以更灵活的组织组件的逻辑 Options API和Composition API代码组织结构的对比

3.Options API vs Compostion API

  • Options ApI 一个功能需要在不同Vue配置项中定义属性和方法,比价分散,不利于维护
  • Composition API 代码是根据逻辑功能来组织的,一个功能所定义的所有api会放在一起(更加的高内聚、低耦合),提高可读性和可维护性。而且基于函数组合的API可以更好的重用逻辑代码,而Vue 2.X Options API中需要通过Mixins重用逻辑代码,更容易发生命名冲突且关系不清。

三、性能提升

1. 响应式系统升级

  • Vue.js 2.x中响应式系统的核心是defineProperty
    在初始化的时候会遍历data中的所有成员,通过defineProperty把成员的所有属性转换成getter、setter,如果data中的属性又是对象,需要递归处理每一个子对象的属性。在初始化时进行,即使没有使用这个属性也会进行响应式处理;
  • Vue.js 3.0中使用Proxy对象重写响应式系统
    使用ES6新增的Proxy对象,Proxy对象的性能本来就比defineProperty要好,另外代理对象可以拦截对象的访问、赋值、删除等操作,不需要初始化的时候遍历所有的属性,另外如果有多层属性的嵌套的话,只有在访问某个属性的时候才会递归处理下一级的属性,使用Proxy对象默认就可以监听到动态添加的属性,而Vue.js 2.x中想要动态添加响应式的属性,需要调用Vue.set方法,而且Vue.js 2.x中还监听不到属性的删除,对数组的索引和length属性的修改也监听不到,Vue.js 3.x使用代理对象可以监听到属性的删除以及数组的索引和length属性的修改操作,所以提升了响应式系统的性能和功能
  • 可以监听动态新增的属性
  • 可以监听删除的属性
  • 可以监听数组的索引和length属性

2. 编译优化

通过优化编译的过程和重写虚拟dom让首次渲染和更新的性能有了大幅度的提升

  • Vue.js 2.x中通过标记静态根节点,优化diff过程
  • Vue.js 3.0中标记和提升所有的根节点,diff的时候只需要对比动态节点内容
    • 引入Fragments(模板中不需要再创建一个根节点,模板里面可以直接放文本内容或者同级的标签,vscode需要升级vetur插件,否则模板中没有唯一的根节点,vscode依然会提示错误。)
    • 静态节点提升
    • Patch flag
    • 缓存事件处理函数,减少不必要的更新操作

2.0的时候模板首先要编译成render函数,这个过程是在构建的时候进行的,编译时会编译静态根节点和静态节点,静态根节点在编译的时候要求节点必须有一个静态子节点,当组件发生变化的时候回通知watcher触发watcher的update,最终执行虚拟dom的patch操作,遍历所有的虚拟节点,找到差异,然后更新到真实的dom上,diff的过程中会比较整个虚拟dom,先比较新旧根节点以及它的属性,然后再对比内部的子节点,2.0中渲染的最小的单位是组件,2.0diff的过程会跳过根节点,因为静态根节点的内容不会发生变化,也就是2.0通过标记静态根节点优化了diff的过程,但是2.0的静态节点还需要进行diff这个过程没有被优化,3.0为了提高性能,在编译的过程会标记和提升所有的静态节点,diff的时候只对比动态节点的内容,3.0新引入Fragments,模板中不需要再创建一个根节点,模板里面可以直接放文本内容或者同级的标签,vscode需要升级vetur插件,否则模板中没有唯一的根节点,vscode依然会提示错误。

3. 源码体积优化

通过优化源码的体积和更好的TreeShaking的支持,减少打包的体积

  • Vue.js 3.0中移除了一些不常用的API
    • 例如:inline-template、filter等,移除的filter可以通过methods或者计算属性来实现。
  • Tree-shaking(依赖ES Module,通过编译阶段的静态分析,找到没有引用的模块,在打包的时候中直接过滤掉以缩小打包体积) 3.0在设计之初考虑到了Tree shaking,内置的组件transtion、keep-alive和内置指令例如:v-model,都是按需引入的,3.0中新增的api如果没有使用的话是不会打包的,但是vue的核心模块都会被打包,在vue.runtime.esm-bundler.js只会打包核心的运行时和响应式系统

四、Vite

Vue.js 3.0的构建工具,vite在法语中是“快”的意思,意味着vite比基于webpack的vue-cli更快。

ES Module

  • 现代浏览器都支持ES Module(IE不支持)
  • 通过下面的方式加载模块

<script type="module" src="..."></script>

  • 支持模块的script默认延迟加载
  • 类似于script标签设置defer
  • 在文档解析完成后,触发DOMContentLoaded事件前执行

1.Vite vs Vue-cli

  • Vite在开发模式下不需要打包可以直接运行

    Vite的工作原理: 因为在开发模式下vite使用浏览器原生支持的ES Module通过import来加载模块,在开发环境下不会打包项目,把所有模块的请求交给服务器来出来处理,服务器处理浏览器不能识别的模块,如果是.vue单文件组件,会调用vue中的模块:compiler-sfc编译组件,并把编译的结果返回浏览器

  • Vue-CLI开发模式下必须对项目打包才可以运行
  • Vite在生产环境下使用Rollup打包
    • 基于ES Module的方式打包
    • 不需要再使用babel把import转化成require以及一些相应的辅助函数,因此打包的体积比webpack打包的体积更小
  • Vue-CLI使用webpack打包

2.Vite的特点

  • 快速冷启动
  • 按需编译
  • 模块热更新

3.Vite创建项目

  • 基于Vue.js 3.0创建项目
npm init vite-app <project-name>
cd <project-name>
npm install
npm run dev
  • 基于模板创建项目
npm init vite-app --template react
npm init vite-app --template preact