Vue.js 3.0的那些事

1,634 阅读8分钟

Vue.js 3.0和2.x的区别

  • 源码组织方式的变化 Vue.js 3.0源码采用TypeScript重写,大型项目的开发都推荐使用类型化的语言,在编码的过程中帮我们检查类型问题,比如给函数传参,类型不匹配会给出相应的错误提示。
    Vue.js 3.0使用Monorepo管理项目结构,把独立的功能模块提取到不同的包中,每个功能模块划分明确,模块之间的依赖关系也很明确,并且每个功能模块都可以单独测试、发布和使用。

packages目录结构

image.png
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环境下,可以用它来测试渲染是否正确,还可以用于序列化DOM、触发DOM事件以及记录某次更新中的DOM操作。
server-renderer:用于服务端渲染
shared:vue内部使用的一些公共API
size-check:私有的包,不会发布到npm,作用是在tree-shaking后检查包的大小 template-explorer:在浏览器运行的时时编译组件,会输出render函数,这个包的README文件提供在线访问地址。
vue:用来构建完整版vue,依赖于compiler和runtime

  • Composition API Vue.js 3.0虽然重写,但90%以上的API兼容2.x。Vue.js 3.0增加了Composition API(组合API),用来解决2.x在开发大型项目时遇到超大组件使用Options API不好拆分和重用的问题。
  • 性能提升 Vue.js 3.0性能大幅度提升,使用proxy(代理对象)重写了响应式代码,并且对编译器做了优化,重写了虚拟DOM,从而使渲染和update的性能有了大幅度提升。此外服务端渲染的性能也提高了2~3倍。
  • Vite 随着Vue.js 3.0的发布,官方提供了一个开发工具Vite。使用Vite在开发阶段测试项目的时候不需要打包可以直接运行项目,提高了开发效率。

Vue3.0不同构建版本

packages/vue
image.png

  • cjs common.js的模块化方案, 这里的两个文件都是完整版的vue,包括运行时和编译器
    • vue.cjs.js 开发版,代码没有被压缩
    • vue.cjs.prod.js 生产版,代码被压缩
  • global 这四个文件都可以在浏览器中直接通过script标签来导入,导入js后会增加一个全局的vue对象
    • vue.global.js 开发版,代码没有被压缩。完整版的vue,包括运行时和编译器
    • vue.global.prod.js 生产版,代码被压缩。完整版的vue,包括运行时和编译器
    • vue.runtime.global.js 开发版,代码没有被压缩。只包含运行时的构建版本
    • vue.runtime.global.prod.js 生产版,代码被压缩。只包含运行时的构建版本
  • browser 这一组文件都包含esm(es module),浏览器原生模块化的方式,在浏览器中可以直接通过<script type='module' src='*'/>的方式来导入这些模块
    • vue.esm-browser.js 开发版,代码没有被压缩。完整版
    • vue.esm-browser.prod.js 生产版,代码被压缩。完整版
    • vue.runtime.esm-browser.js 开发版,代码没有被压缩。只包含运行时的构建版本
    • vue.runtime.esm-browser.prod.js 生产版,代码被压缩。只包含运行时的构建版本
  • bundler 这两个文件没有打包所有的代码,需要配合打包工具来使用。都使用es module模块化的方式,内部通过import导入了runtime-core
    • vue.esm-bundler.js 完整版,内部还导入了runtime-compiler也就是编译器
    • vue.runtime.esm-bundler.js 运行时版,内部只导入了运行时,是vue的最小版本。在项目开发完毕后,重新打包的时候只会打包使用到的代码,可以使vue体积更小

Composition API

设计动机

Vue 2.x在开发中小型项目的时候已经很好用。但是使用Vue 2.x在开发需要长期迭代的大型项目时,也会有些限制。在大型项目中可能会有一些功能复杂的组件,我们在看别人开发的组件的时候很难看懂,原因是Vue 2.x版本的组件开发采用的是Options API
Options API是指使用包含一个描述组件选项(data、methods、props等)的对象来创建组件的方式。Options API开发复杂组件,同一个功能逻辑的代码会被拆分到不同选项。
下面来看一个Options API简单的案例: image.png
这段代码描述的是当鼠标移动的时候把鼠标的位置展示在页面上。鼠标的位置在data选项中对应position,注册鼠标的mousemove事件在生命周期钩子函数created中,还需要在组件销毁的时候移除事件,最后还需要在methods中添加一个函数来记录鼠标位置。
现在设想一下,如果需要给这个组件添加一个新的功能,如新增一个搜索的功能,那么需要在多个选项中增加代码。如果代码量多的话,那么会不时的拖动滚动条来查找代码。另外使用Options API还难以提取组件中可重用的逻辑。虽然Vue 2.x中有Mixin混入的机制,可以把组件中重复的代码提取并重用。但是Mixin使用过程也有问题,如命名冲突、数据来源不清晰。

Composition API 是Vue 3.0新增的一组API,是一组基于函数的API,让我们可以更灵活的组织组件的逻辑。
image.png
这段代码是使用Composition API重新写的逻辑。首先把获取鼠标位置的逻辑封装成了一个函数,其他组件也可以直接使用这个函数所封装的功能。我们只需要把useMousePosition提取到一个模块中,然后在其他模块中通过import导入即可。当我们需要新增功能的时候,例如搜索功能,我们只需要再添加一个useSearch函数,把搜索功能封装起来。将来哪个组件中需要这个功能,只需要在这个组件的setup函数中来调用useSearch函数。
相对于Options API,这样做的好处是查看某个逻辑的时候,只需要关注具体的函数即可,当前的逻辑代码都封装在函数内部。

性能提升

响应式系统升级

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

编译优化

  • Vue 2.x中通过标记静态根节点,优化diff的过程。
  • Vue 3.0中标记和提升所有的静态根节点,diff的时候只需要对比动态节点内容。在Vue 3.0中新引入了Fragments,也就是片段的特性,模板中不需要创建一个唯一的根节点,模板里面可以直接放文本内容,或者很多同级的标签。在VS Code中需要升级vetur插件,否则模板中如果没有唯一的根节点,VS Code会提示有错误。

优化打包体积

Vue 3.0中移除了一些不常用的API,比如:inline-template、filter等,让最终的打包体积变小。另外,Vue 3.0对Tree-shaking的支持更好,Tree-shaking依赖es module,通过编译阶段的静态分析找到没有引入的模块,在打包的时候直接过滤掉,让打包后的体积变小。

Vite

Vite是一个 web 开发构建工具,由于其原生 ES 模块导入方式,可以实现闪电般的冷服务器启动。
通过在终端中运行以下命令,可以使用 Vite 快速构建 Vue 项目。
使用 npm:

$ npm init vite <project-name> -- --template vue
$ cd <project-name>
$ npm install
$ npm run dev

或者 yarn:

$ yarn create vite <project-name> --template vue
$ cd <project-name>
$ yarn
$ yarn dev

Vite特点

  • 快速冷启动
  • 按需编译
  • 模块热更新 Vite vs Vue-Cli
  • Vite 在开发模式下不需要打包可以直接运行;Vue-Cli 开发模式下必须对项目打包才可以运行
  • Vite 在生产环境下使用Rollup打包,基于ES Module的方式打包;Vue-Cli使用webpack打包