XIAOJUSURVEY的Vue3升级之路

前言

XIAOJUSURVEY是由公司内部沉淀、重新设计并开源的系统,因此也继承了内部使用的Vue2框架。但是随着vue2逐渐停止维护,vue3的生态建设已经日趋完善与稳定,升级Vue3版本已势在必行。

文内项目Github:XIAOJUSURVEY

作者:nilnoop


背景

经梳理,工程中需要升级的配套库包含vue、vue-router、vuex、Element-UI、VueDraggable、wangeditor、Vue-Cli等,涉及到的工作量巨大。为了控制变更范围、保持功能稳定,先做必须的升级,比如虽然Vite提供了内置的TS支持可开箱即用,本次升级仍保留原来的JS写法,后续再逐步改造成TS。

接下来就逐个看一下升级过程。

vue

不知不觉间vue已经走过了第十个年头,在前端技术日新月异的今天,已经是一个不再年轻的框架。但是vue3仍然为社区带来了新的活力。重构的响应式系统、更好的代码组织方式(composition api)、更优秀的diff性能、解耦的视图层渲染,甚至更优雅的代码组织方式也让更多人了解并熟知了mongo repo的代码组织范式,并引起了社区的极大关注。

由于Vue3的一大亮点是升级了Composition API,支持更好的逻辑复用,更有利于大型项目的维护。但是考虑到升级顺利,原组件仍保持vue2的Option API写法。但是部分breaking change还是需要手动升级的,包括但不限于:

1、ModelValue

v-model的props名称变成了ModelValue,这一点在子组件接收props的时候需要修改的props名字。当然也可以使用 defineModel 宏来简写。但是要注意版本需要为3.4+

// vue2中v-model的语法相当于下面的结果
<ChildComponent :value="pageTitle" @input="pageTitle = $event" />

// vue3中v-model的语法相当于下面的结果
<ChildComponent
  :modelValue="pageTitle"
  @update:modelValue="pageTitle = $event"
/>

2、插槽slot

// vue2写法-使用插槽
<div slot="body"></div>
// vue3写法-使用插槽
<template #body></template>

注意如果在vue组件中使用了渲染函数,那么插槽的渲染方式也发生了变化,改成了函数调用。

// vue2写法
this.$scopedSlots.header

// vue3写法
this.$slots.header()

3、后缀

资源import的方式,必须要显示指定.vue后缀

// vue2写法,可以省略文件后缀
import HomePage from './HomePage'

// vue3写法,必须携带.vue后缀
import HomePage from './HomePage.vue'

这是因为vue2中,vue-loader对资源后缀做了兼容。在vite中,所有import声明被设计为必须强制携带后缀,并后在vue-cli的后续计划中也会取消对省略后缀写法的支持。详见:import *.vue file without .vue will not work · Issue #178 · vitejs/vite · GitHubDescribe the bug For example A file named tsc.vue, import tsc from "./tsc.vue"; It's ok,but import tsc from "./tsc"; not work,report Failed to load module script: The server responded with a non-JavaScript MIME type of "text/html". Stric...icon-default.png?t=N7T8https://github.com/vitejs/vite/issues/178#issuecomment-630138450

4、jsx写法

vue文件中使用jsx写法,必须在script标签上显式指定lang="jsx"

// vue2写法,可以不声明lang="jsx"
<script>
/* jsx代码 */
</script>

//vue3写法,必须声明lang="jsx"
<script lang="jsx">
/* jsx代码 */
</script>

想要了解更多可以参考官网的迁移指南:Vue 3 迁移指南

Vue Router

vue2中的rouer,需要先初始化,然后在初始化Vue实例的时候传入。

// router.js
import VueRouter from 'vue-router';
export const router = new Router({
  mode: 'history',
  base: '/management',
  routes,
})

// main.js

new Vue({
  router,
  ...
})

vue3中的router除了创建方式不同外,挂载的方法也改成了通过.use方法进行链式挂载。

// router.js
import { createRouter, createWebHistory } from 'vue-router'

export const router = createRouter({
  history: createWebHistory('/management'),
  routes,
})

// main.js
import { createApp } from 'vue'
import { router } from './router'

createApp(App).use(router).mount('#app')

同时<router-link />标签上不再支持添加class与tag,需要在slot元素上添加。

Pinia

pinia作为官方推荐的全局状态管理库,和vue3的composition写法更搭,用起来也比vuex更灵活,不必一板一眼地写action与commit。但是既然有了composition api,我们完全可以通过简单的方式实现一个状态管理:

import { reactive } from 'vue'

const state = reactive({
    count: 0
})

export const useStore = () => {
    const setCount = (value) => {
        state.count = value
    }
    return [state.count, setCount]
}

那么为什么还需要使用pinia呢?原因有以下几点:

  1. 开发工具支持。开发过程中可以通过浏览器插件vue.js devtools查看并追踪pinia的状态、事件,也可以方便地进行时间回溯调试。如果没有开发工具的支持,就只能四处console.log + debug了, 尤其是在大型项目来说,简直折磨。
  2. 热更新。热更新时不会丢失当前的state。前端er,你也不想走完长长的业务流程因为热更新丢失状态从头点一遍吧?
  3. SSR支持。不会造成跨请求状态污染。

不得不说vue的官方确实很有作为,官方推荐就是最佳实践。所以XIAOJUSURVEY也升级了pinia作为状态管理库。

Vite

vite基于浏览器的原生es module带来的动态加载和esbuild的模块预编译带来的快速启动,对于开发体验带来的提升是巨大的。而且和vue是官配,对vue提供第一优先级支持,一经推出就席卷了社区,甚至成为众多非vue项目(angular、svelte、solidjs等)的官方推荐。因此对本项目来说,vite是开发脚手架的不二之选。

另外说一句esbuild是真滴快,而且非常简单易用。各种功能只通过参数指定就可以,没有复杂的打包配置,内置了ts支持,如果大家有一些库需要打包,可以尝试一下,对比下rollup各种复杂的插件配置以及各版本之间的兼容问题,esbuild非常值得尝试。

诚然vite在当前阶段还有一些小问题,比如:

  1. 开发环境与生产环境产物不一致。开发期间使用esbuild编译模块、生产环境使用rollup打包,有可能出现两个环境产物不一致的情况,而且一旦遇到很难排查。
  2. 由于启动时不对资源进行打包,首屏会根据资源的依赖加载资源,可能造成请求过多、浏览器卡顿、甚至卡死、崩溃的的问题。但是xiaojuSurvey还远远没有达到这种体量。

MPA支持

由于项目具有B端管理页和C端投放页两个html入口,因此需要使用mpa模式。vite本身支持mpa,只需要在vite.config.ts中将 appType 设置为mpa即可。但是使用体验并不美好,比如说文件路径不美观。

vite中文件的路径就是浏览器访问的路径,可能很长。以XIAOJUSURVEY中的B端入口文件为例,它的路径是/mangement/index.html,那么浏览器访问的路径就是 localhost:8080/management/index.html。因此我们需要一个插件,将一个短的、便于记忆的路径映射到长长的html路径上。

在vite的插件市场找来找去,选中了功能最契合需求的 vite-plugin-virtual-mpa 插件,它具有以下特性:

  1. 路径映射,集成了 ·connect-history-api-fallback 来实现从路径到html文件的映射。这也是我们寻找插件的刚需。
  2. 从插件名字可以看出来,它可以生成虚拟的(virtual)html入口文件。例如xiaoju-survey中有B端C端两个入口,它们可以共享一个html模板,在访问C端链接的时候读取在内存中生成“虚拟”html文件,并可以通过ejs注入rem代码,提供了非常高的灵活性。
  3. 通过文件夹自动扫描页面,避免html太多时的繁琐配置,等等。

Vue Draggable

由于vue3一些升级的breaking change,拖拽库的api也有一些变化。

vue2使用库vuedraggable是的写法如下:

<draggable v-model="myArray">
   <div v-for="element in myArray" :key="element.id">{{element.name}}</div>
</draggable>

vue3对应使用vuedraggable的next版本,数据对象与索引需要通过作用域插槽来获取,写法如下:

<draggable v-model="myArray" itemKey="id">
  <template #item="{element, index}">
    <div>{{element.name}}</div>
   </template>
</draggable>

ElementPlus

这部分比较简单,可以直接使用使用官方的迁移工具,见文档:https://element-plus.org/zh-CN/guide/migration.html

剩下可能有其他的小问题等小问题还需要人工回归验证,再逐个修复, 比如自定义主题变量不生效。相对于其他库,Element-UI的整体迁移过程还是很顺滑的。

升级感受

在升级框架之前,vue2和vue3的项目都开发过了一些。也遇到了一些预料之外的问题,拜繁荣的社区所赐,都顺利解决了。升级后的同事们的第一个感受是开发启动快,在后续的局部重构与优化中,项目的结构与代码逻辑也基于composition api变得更清晰。

同时,我们惊喜地发现,社区参与建设的朋友也多了起来。看来历史的车轮滚滚向前,想要项目保持活力,还是要保持技术栈的迭代不能停。

全部变更可以参见pr:Feature/vue3 by nilnoop · Pull Request #98 · didi/xiaoju-survey · GitHub由于vue2及周边生态已经停止维护,同时vue3的生态建设已经日趋完善与稳定,进行了vue3的升级。主要变动如下:vue及其必相关必要依赖的升级,包括vue,为保持功能稳定,升级后原option写法保持不变,待升级稳定后再优化至composition写法。升级部分break change写法,如slot="body" -> vue routervuex,并解耦部分写法至 hook,例如this.app.store => useStore()vuedraggableelement-ui -> element-plus脚手架从vue-cli升级至viteicon-default.png?t=N7T8https://github.com/didi/xiaoju-survey/pull/98  

关于我们

感谢看到最后,我们是一个多元、包容的社区,我们已有非常多的小伙伴在共建,欢迎你的加入。

Github:XIAOJUSURVEY

社区交流群

微信:

Star

开源不易,请star 一下 ❤️❤️❤️,你的支持是我们最大的动力。
​​​​

  • 17
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
升级Vue2到Vue3需要注意以下几点: 1. Vue3将成为官方的重点研发版本,因此周边生态、组件、插件等都会以Vue3为默认版本进行维护和更新,而Vue2的组件插件库将逐渐停止维护和迭代更新。因此,为了跟上时代的步伐,建议转向Vue3。\[1\] 2. 在Vue2中,全局挂载(Vue.prototype)的写法在Vue3中不再适用,需要修改为使用createApp函数来创建应用,并使用app.config.globalProperties来进行全局挂载。\[2\] 3. 组件库的语法也会有所修改,例如element-UI改用elementPLus,引入方式和部分组件用法都有所改变。需要根据具体的组件库文档进行相应的修改。\[2\] 4. 废弃语法也需要进行修改,例如插槽语法的改写,以及一些被废弃的语法需要改成对应Vue3的语法。需要仔细查看Vue3的官方文档进行相应的修改。\[2\] 5. 生命周期的命名也有所修改,例如destroyed生命周期选项被重命名为unmounted,beforeDestroy生命周期选项被重命名为beforeUnmount。需要注意修改相应的生命周期钩子函数的命名。\[2\] 6. Vue3中的v-model用法也有所改变,需要参考官方文档进行相应的修改。\[2\] 7. 在Vue3中,无法直接使用this来调用上下文方法,需要使用proxy来获取data和methods的内容。需要注意修改相关代码。\[2\] 总之,升级Vue2到Vue3需要仔细阅读Vue3的官方文档,并根据具体情况进行相应的修改。逐步替换Vue2框架为Vue3,并按照Vue3的composition API结构来编写新增的页面和组件。\[3\] #### 引用[.reference_title] - *1* *2* [手摸手带你玩转Vue3——Vue2升级Vue3](https://blog.csdn.net/weixin_46709512/article/details/124966678)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Vue2 大型项目升级 Vue3 详细经验总结](https://blog.csdn.net/Kevinblant/article/details/126238184)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值