vue3开发实践总结

背景

前段时间需要排Q3的前端技术项,刚好我一直想做vue3项目很久了,就与领导商议了一下,把一个线上小项目改造成vue3版本的。
这是个PC端项目,作为微前端被内嵌至别的应用之中,项目不大,只有三个界面,不过这三个界面都是基础核心业务模块,里面内嵌了树、动态布局、动态筛选等N个业务组件。
在最近一个月内,经过断断续续的开发,昨天项目发布到生产环境。现总结一下这段实践。

技术栈

  • vue全家桶:vue3.2、vue-router4.0、pinia2.0
  • 组件库:element-plus 2.2.x、vxetable 4.2.x
  • 加强类:typescript、eslint、prettier
  • 打包构建:vite 2.9.x
  • 微前端相关:vite-plugin-qiankun

之所以在使用element plus的基础上,又添加了vxetable的使用,是因为之前的项目表格都是使用的vxetable,后者在复杂表格的实践上,功能是远超过element table

具体开发过程

  • 使用的 npm init vue@latest 脚手架初始化工程
  • 删除无用代码,引入组件库、axios、sortable等业务包
  • 业务界面、业务组件通过组合式api全部重写(之前的代码已经成了巨石应用)
  • 全局组件部分使用组合式api重写
  • 微前端整合
  • 代码优化、注释,上线

ts的引入

之前开发react的时候,使用过ts,不过开发vue2项目的时候,由于其对ts支持的不友好,都没有使用ts
由于vue3对ts支持的比较好,再加上ts目前作为前端开发届的标配,没有理解不添加使用ts

选择组合式api(Composition API

个人觉得是vue3相对于vue2开发体验改变最大的地方,完全颠覆了之前的option写法。
作为当年第一波吃vue2螃蟹人,我对option写法很是喜欢,并且制定了一系列规范来写更好的option,如data里面的数据,按模块顺序、分开书写vue2 的option属性需要按顺序排列,不能留空(详见:前端规范 - vue2开发规范
在之前的vue2项目中,单vue组件过大的话,的确会出现上下横跳的费劲场景,一个业务逻辑需要在data、watch、methods中来回书写
在这里插入图片描述
使用组合式api的确改变了开发体验。上图可以很形象的总结出变化,以后写代码,单vue组件内比较容易划分模块
而组合式api代理的所有模块都是import导入这点,与react又是一大相似点

setup语法糖

相对比第一波吃vue3螃蟹的人,我入场的时候已经支持了setup语法糖,那没理由不使用它

组合式函数来代替mixin

组合式函数,因为与react hooks的思路类似,业内也叫vue hooks
个人对vue2的mixin是又爱又恨,在拆分巨型vue文件时,mixin往往是利器,但其自身的缺陷(数据来源不明确、数据覆盖等),又让我不敢随意使用mixin
组合式函数的出现,就是为了替代mixin;在实际的开发中,全局、模块内也是创建hooks文件夹,里面放js文件
但hooks也不是100%的好,因为其传参、返回都是显式定义,因此会对上下文顺序有依赖

provide、inject来做全局应用

在vue2的时候,我推荐将http请求、url链接统一归纳管理,然后挂载在vue prototype上,就可以直接通过this进行调用,如下面的代码

this.$http.get(this.$listUrl.bom.getList, ...)

现在就不行了,因为组合式api直接没有this了!
替代方案1:每个界面都引用 $http$listUrl,这个属于下策
替代方案2:在main.ts定义全局变量,然后每个vue组件通过getCurrentInstance获取调用,如下面代码
这种跟微信小程序的获取全局变量很是类似,但是不好用,引用的代码很多,vue官方也不建议使用

// mian.ts中定义全局变量
app.config.globalProperties.$http = $http

// 业务vue中
import { getCurrentInstance } from 'vue'
const { ctx } = getCurrentInstance() as any
ctx.$http.get

代替防范3:使用provide、inject来做全局应用
在main.js定义全局变量,然后每个vue组件通过inject获取,如下面代码
虽然不如vue2中使用的便捷,不过也容易理解

// mian.ts provide全局变量
app.provide('global', {
  $http,
  $listUrl
})

// 业务vue
import { inject } from 'vue'
const global = inject('global')
global.$http.get(global.$listUrl.MATERIAL_SELECT_TREE_INFO, { params }).

对vue2代码的兼容

很多项目无法升级到vue3的一大原因是因为vue3的周边生态不够完善,尤其是公司内部的生态支持
我这次升级的业务使用到了两个复杂的业务组件,直接通过npm引入是不行的,只能拿到本地来调整
vue3也支持之前的option写法,不过个别api需要做出改动,我遇到的改动不算很多,具体如下:

  • emit需要显式定义好
  • 自定义v-model的改动
  • 生命周期的改动

那些小坑你一把的改动

v-model 的改动,vue2是value,现在是modelValue

prop: value -> modelValue;
event: input -> update:modelValue;

<ChildComponent :value="pageTitle" @input="pageTitle = $event" />
<ChildComponent v-model="pageTitle" />

<!-- would be shorthand for: -->

<ChildComponent
  :modelValue="pageTitle"
  @update:modelValue="pageTitle = $event"
/>
外部调用组件内部方法、属性,需要显式抛出

否则调用不到

// 子组件
// 定义方法
function open() {...}
// 显式抛出
defineExpose({
  open
})

那些废弃了的api

  • eventBus 这个还好,本身算是老古董,我也一直不建议使用
  • filter 这个我很难过,从我接触vue1.x版本开始,过滤器就是我喜欢vue的一个特性,现在废弃了有点舍不得

element plus的升级

作为vue3的对应版本,能感受到element plus的努力

  • icon引入方式的变化 - 这个影响最大
  • size取消了mini的规格
  • button type=“link”的弃用
  • treeV2 树的虚拟滚动添加 - 有小坑需要踩
  • tableV2 表格的虚拟滚动添加 - 没具体使用,估计也会有小坑

构建工具选择vite

这算是开发过程中体验最舒服的地方了,启动秒起、代码修改后界面秒刷新
默认打包命令、文件夹与之前的vue cli默认一致,可以无缝对接公司的devops系统
不好处:
由于vite使用rollup来打包,因此你需要做一些配置的话,需要查阅rollup的api文档,相当于你当年在webpack踩的坑,现在又需要重新走一遍

Vuex -> Pinia机会可以忽略的改动

我算是个vuex的保守使用者,在不需要共享数据的时候,我是不建议使用vuex的
这次项目改动使用的Pinia,属于常规操作并且地方不多,除了Pinia删除了mutations这个小改动外,没感觉到有多大的变化

cdn的引入

vite是支持静态js通过cdn来引用的,这样会减少加载包的大小
社区有很多解决方案,都是通过rollup的扩展能力
不过我使用cdn引入,与微前端的模式有冲突,后面放弃了cdn的引用

<!-- index.html界面引用cdn文件(要引公司内部的cdn,不能引用第三方cdn) -->
<script src="//xxcdn/vue/3.2.37/vue.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/vue-demi@0.13.7"></script>
...
// vite.config.ts
// 需要install下面的两个包
import commonjs from 'rollup-plugin-commonjs'
import externalGlobals from 'rollup-plugin-external-globals'
...
const globals = externalGlobals({
  vue: 'Vue',
  'vue-router': 'VueRouter',
  'vue-demi': 'VueDemi',
  pinia: 'Pinia',
  axios: 'axios',
  'element-plus': 'ElementPlus',
  '@element-plus/icons-vue': 'ElementPlusIconsVue',
})
const plugins = process.env.NODE_ENV === 'production' ? [] : [commonjs(), globals]

defineConfig({
  plugins: [vue(), ...plugins],
  build: {
    target: 'es2015',
      rollupOptions: {
        external: ['vue', 'vue-demi', 'pinia', 'vue-router', 'element-plus', '@element-plus/icons-vue'],
        plugins: [
          commonjs(),
          globals
        ],
      },
    },

微前端的适配

一早就知道qiankun的官网不支持vite,但又舍不得vite的开发体验,一开始想做成本地vite+打包使用webpack的模式,
不过还是在社区里面找到了解决方案,通过vite-plugin-qiankun来实现,虽然最后无法实现动态插入publicPath,不过瑕不掩瑜,完全不影响生产环境使用

其他开发体验

  • 使用proxy代替了Object.defineProperty做数据绑定这点,对开发体验小有提升,不需要再写$set数组splice模拟通过下标修改
  • Volar不是那么的好用,无法进行详细的配置,格式化的时候对组件多属性的折叠不友好,这里推荐使用prettier做代码格式化;而且
  • vsode开发体验,不知是个人vscode的问题,感觉代码提示、输入反馈,不如vue2项目的体验来的好,后续需要持续关注
  • vue devtools升级到了新版本,体验倒是不错

性能提升

说实话,由于数据量不是十分大,直观体验上,性能没有多少提升……后续需要找一下经典场景来测试一下

总结

这个项目也算是完整的从0到1开发一个vue3项目,虽然项目不算大,但麻雀虽小五脏俱全,该有的体验也都把玩了一下。
总体来说,vue3带来了一些新内容,但还是属于框架内的改动,无法影响到整个前端圈。如果是之前平稳运行的项目,不建议推倒重构
到vue3版本,新项目或者小项目重构,可以大胆使用vue3
vue3是vue的未来,现在也已经很成熟了,后续的新项目,都推荐使用vue3来做的

后续

近期需要根据此项目,抽出脚手架来,供团队内使用。
还需要多学习总结,打造vue3版本的代码规范+最佳实践,以及ts的代码规范

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值