vue3 + element plus + vite 迁移实践

背景
最近入职了一家新公司,需要搭建一个后台管理系统,我想着这太简单啦,react antd pro一把梭。然后领导喜欢vue,说vue简单,写起来快…我说行嘛,刚好没写过vue3,那就全用最新技术,vue3、vite、element plus直接上。然而我还是想简单了,后端大哥选择了一个叫go-admin的框架,前端是vue2,element admin 那一套,说里面包含了用户系统的基础功能,权限神马的都有,前后端都不需要写这部分代码了。我…我说行嘛,做业务,效率优先,就用这个吧。然而我心里想的是,我自己按照这个架子用自己想用的技术搞一套出来不就行了,反正我有时间。
技术方案
当前的技术栈及相关依赖版本,vue 2.6.11,vuex 3.5.1,vue-router 3.4.7,vue cli 4.5.13,element ui 2.13.2
目标
vue2.x 升级到vue 3.x
element ui 升级到 element plus
vue cli 升级到 vite
由于我是写react出身,所以有两种方案
使用react + antd 自己按当前项目的样子实现一套
基于当前项目渐进升级
方案一消耗的时间会比较长pass掉,那就直接采取方案二基于当前项目来。搜索引擎 xx一番,发现了这个gogocode Element UI 到 Element Plus 升级指南,唔,那就按照这个方法操作吧,切分支,弄。
实践

  1. 精简项目
    gogocode 会转换src目录下的代码,所以先对项目进行瘦身,删除无用的代码和组件,防止无关紧要的东西形成干扰,转换出现错误等。

  2. GoGoCode 升级
    按照 Element UI 到 Element Plus 升级指南 操作。
    vue2 升级到vue3 gogocode -s ./src -t gogocode-plugin-vue -o ./src
    相关依赖升级 gogocode -s package.json -t gogocode-plugin-vue -o package.json
    elemen ui升级 gogocode -s ./src -t gogocode-plugin-element -o ./src

  3. 错误修复
    经过以上两步操作,初步的升级完成啦,run dev跑一下,咔,命令行报错
    Cannot set properties of undefined (setting ‘preserveWhitespace’)看一下,是vue.config.js 的一行代码报错options.compilerOptions.preserveWhitespace=trueemm,就是说compilerOptions是undefined,好说,默认值兜底,加一行options.compilerOptions=options.compilerOptions||{},错误成功解决。
    继续run dev,又报错了… options has an unknown property ‘overlay’ 还是vue.config.js,dev Server里配置了这个属性,估计是新的vue cli不支持这个写法吧,查文档,原来是webpack5的问题,overlay的配置变啦,外面要包一层client…错误解决
    再run,又来错误webpack < 5 used to include polyfills for node.js core modules by default.好嘛,项目在处理路由的时候用到了path,根据报错提示,安装一下path-browserify,再在vue.config.js里加个别名配置,path: ‘path-browserify’,错误解决
    再次run dev,OKOK,项目跑起来啦,额,样式怎么不太对,侧边栏和导航栏的样式都有点问题
    vue3 + element plus + vite 迁移实践_第1张图片
    预期效果
    vue3 + element plus + vite 迁移实践_第2张图片

再点一点菜单,好家伙,压根不能跳转,挨个解决问题先
右上角样式,没有垂直居中,改下class…很简单
左侧头部应该是有两个菜单的,但是现在只展示了三个点… 仔细排查,看代码,没有啥问题,又看了下这个地方用的是el-menu组件,再查element-plus文档,终于发现玄机,el-menu 的ellipsis 属性默认为true,好吧,加上一行 :ellipsis = false 搞定
再看菜单颜色,有一段是白色的,去看代码发现是这样的 :background-color=“$store.state.settings.themeStyle === ‘light’ ? variables.menuLightBg : variables.menuBg"关键在variables 这个变量上,再一看 import variables from ‘@/styles/variables.scss’;从scss导入进来的,打印一下发现variables 是个空对象,怪不得样式不对,再去看看vue cli文档,css modules的问题,把文件名改成variables.module.scss 就可以了,成功解决
然后看路由跳转的问题,看了一下路由相关的代码,基础页面是静态路由,管理页面都是动态路由,菜单和路径都是接口返回的,动态路由都无法跳转,说明动态路由注册出现了问题,看一下代码 router.addRoutes(accessRoutes)去vue-router官网查查,发现新版本没有addRoutes 方法了,只有addRoute,也就是说路由要一个一个添加。没有问题accessRoutes是个数组,遍历添加就好了
accessRoutes.forEach((item) => {
router.addRoute(‘/’, item);
});
好啦,这些错误修完,项目已经能正常运行啦,每个页面点一点,还是有一些小瑕疵,继续修。
4. 细节修复
跳转页面的时候回出现个没有内容的error message,控制台又看不到报错,要解决。先找到哪里的代码弹出的message,页面跳转的时候出现,最有可能的就是路由相关的代码,查一查果然,路由守卫里写了 一段try catch代码,在catch里写了Message.error(error || ‘Has Error’);error是对象,这里的message就弹出了空,错误被吃掉了,控制台也看不到,那就打印一下吧。错误出现了 Catch all routes (”") must now be defined using a param with a custom regexp. 就是说这个全匹配的路由出了问题,不能直接写 ,要写正则,找到代码 asyncRoutes.push({path:‘‘,redirect:’/‘,hidden:true})结合 vue router迁移文档,修改为 asyncRoutes.push({path:’/pathMatch(.)*’,redirect:‘/’,hidden:true}) 成功解决
部分页面出现警告 Vue received a Component which was made a reactive object.意思说组件被搞成了响应式的,会浪费性能,看代码发现雀食,一些组件在模板里当做组件属性使用,都挂在了data上。解决方法很简单,我们升级了vue3呐,直接setup语法用起来。setup() {return {Components}}完美解决
scss 有警告 v-deep usage as a combinator has been deprecated. use deep( inner-selector ) instead深度选择器的问题,这个简单,直接按照提示改就好
关于el-button,type = text需要修改为 text type = link需要修改为 link
关于组件的size,只有 large、default、small三种,mini神马的都不行
侧边菜单点一点,收起的时候,卡的一p,而且图标也不见了,在网上搜了搜,都是些没用的信息,移除动画效果呀,都不行,只能对着element plus 折叠菜单的demo看,终于发现了端倪,项目里的 menu-item 被div包裹了一层,而这个组件的样式选择器用的是 > 多了一层div就找不到了撒。根据div 的class 改下样式,okk。
vue router还有警告 can no longer be used directly inside or .哦,router-view和keep-live的嵌套顺序有问题,改改改








这下好啦,错误和警告全部消除,vue3和element plus的升级完成,下一步需要把vue cli迁移到vite。
5. vue cli 升级到vite
网上搜索了一番,没有什么转换工具,那只能自己搞啦,首先用vite创建一个vue 3 + ts的工程,然后就照着扒就好啦。
把vue cli相关的依赖删除掉
按照刚刚生成好的vite 模板,安装一下vite相关的依赖,ps:这个时候可以直接上pnpm,安装依赖真的快
创建vite.config.js,把内容先copy一下
package.json 的命令替换一下,都换成vite的
基本的东西搞好了,看看vue.config.js里用了哪些插件,先把影响功能的搞一搞,打包相关的不管,主要有两个插件
html plugin,就是可以在html里面用ejs语法插入变量的
svg plugin,svg雪碧图插件,高效复用svgicon
vite官方虽然没有,但是社区已经有了相关的插件,vite html plugin 和 vite svg plugin。直接按照官网配置即可,另外还有一些插件element plus 自动导入、打包分析等等,我直接把配置文件放出来
import { defineConfig } from ‘vite’;
import vue from ‘@vitejs/plugin-vue’;
import Icons from ‘unplugin-icons/vite’;
import IconsResolver from ‘unplugin-icons/resolver’;
import AutoImport from ‘unplugin-auto-import/vite’;
import Components from ‘unplugin-vue-components/vite’;
import { ElementPlusResolver } from ‘unplugin-vue-components/resolvers’;
import Inspect from ‘vite-plugin-inspect’;
import { createSvgIconsPlugin } from ‘vite-plugin-svg-icons’;
import { createHtmlPlugin } from ‘vite-plugin-html’;
import jsx from ‘@vitejs/plugin-vue-jsx’;
import { visualizer } from ‘rollup-plugin-visualizer’;
import defaultSettings from ‘./src/settings’;
import { resolve } from ‘path’;
const autoprefixer = require(‘autoprefixer’);
const name = defaultSettings.title || ‘HT Mateverse’; // page title
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
jsx(),
createHtmlPlugin({
inject: {
data: {
name,
},
},
}),
Icons({
autoInstall: true,
}),
Inspect(),
AutoImport({
imports: [‘vue’],
resolvers: [ElementPlusResolver(), IconsResolver()],
}),
Components({
resolvers: [
ElementPlusResolver(),
IconsResolver({
enabledCollections: [‘ep’],
}),
],
}),
createSvgIconsPlugin({
iconDirs: [resolve(process.cwd(), ‘src/icons/svg’)],
symbolId: ‘icon-[name]’,
customDomId: ‘svg__icons__dom’,
}),
visualizer(),
],
resolve: {
alias: {
‘@’: resolve(__dirname, ‘src’),
‘#’: resolve(__dirname, ‘types’),
path: ‘path-browserify’,
‘vue-i18n’: ‘vue-i18n/dist/vue-i18n.cjs.js’,
},
},
css: {
postcss: {
plugins: [autoprefixer],
},
},
});
文件配置好啦,run个dev试试,果不其然报错
Failed to resolve import “./App” from “src\main.js”.愣住,什么情况,文件目录没问题呀,怎么找不到,查查vite文档, resolve.extensions 配置,唔,省略的扩展名里没有.vue。加一下?然而官网里说(还是老老实实补全后缀吧):
导入时想要省略的扩展名列表。注意,不 建议忽略自定义导入类型的扩展名(例如:.vue),因为它会影响 IDE 和类型支持。
require is not defined,emm vite是es module 这套,require肯定是不行的,改一改,代码里require改成import,vite是支持glob 批量导入的,一些使用require的批量导入也都需要替换掉
process is not defined 代码里读取环境变量的时候又又报错了,再看看 vite 环境变量的文档,有两个点需要修改
环境变量需要通过import.meta.env获取
在env文件中声明的变量,需要以VITE 开头,否则是无法注册到项目中的
!!! 注意,主要的错误就这两个,require相关的代码需要先改好,否则会出现一些莫名奇妙的错误,把require的代码改了,自然就好了…
收官
run 个 dev,vite真的是名不虚传,10秒内启动项目。迁移和升级都完成了,在点一点吧,发现还要两个小问题
vue-i18n 报了个警告, You are running the esm-bundler build of vue-i18n. It is recommended to configure your bundler to explicitly replace feature flag globals with boolean literals to get proper tree-shaking in the final bundle. 讲道理我没懂这玩意儿啥意思,一番搜索,在vite.config配置个别名,‘vue-i18n’: 'vue-i18n/dist/vue-i18n.cjs.js’就好了。后面要仔细研究下
修改页面的js代码时,热更新报错 parentComponent.ctx.deactivate is not a function 刷新一下就好,修改模板代码也没问题…又去搜索了一下,很多都说在keep-alive下面的component上配置key,然而我试了试,并不行,最终在github上找到了此pr github.com/vuejs/core/…。是keep-alive相关的问题,pr还没合并,那我们怎么搞呢。很简单,keep-alive的热更新问题,生产环境是不需要热更新的,只需要判断下环境,开发环境不用keep-alive就好啦。

完美,终于可以使用最新的vue技术栈啦,激动 总结 项目在精简后只有基本的用户信息和权限相关的功能,十几个页面,并不复杂。升级共花费了一周的时间,我的时间充裕,理论上肯定是可以压缩的。后续还有一些工作要做,生产环境打包的配置,包大小的优化。以及使用pinia替换vuex。 好啦,到此结束。

你可能感兴趣的:(vue3,vue.js,javascript,前端)