环境更新
package.json
// common
+ "@vue/compat": "^3.2.47",
"vue": "2.6.11" -> "3.2.47",
"vue-router": "3.1.6" -> "4.0.6",
"vuex": "3.6.2" -> "4.1.0"
+ "@vue/compiler-sfc": "^3.2.47",
"vue-loader": "15.9.8" -> "17.0.1",
- "vue-template-compiler": "2.6.11"
"webpack-cli": "4.9.0" -> "4.10.0"
"webpack-dev-server": "4.3.0" -> "4.11.1"
"vue-loader": "15.9.8" -> "17.0.1"
// modules
- "element-ui": "2.15.9"
+ "element-plus": "2.2.0"
+ "@element-plus/icons-vue": "2.1.0"
- "vue-code-diff": "^1.2.0"
+ "v-code-diff": "1.3.0"
"vue-form-json-schema": "2.9.2" -> "3.0.0-alpha.0"
"@fortawesome/vue-fontawesome": "2.0.8"->"3.0.3"
// test
"vue/test-utils": "1.3.4" -> "2.3.2"
+ "@vue/vue3-jest": "27.0.0"
+ "babel-jest": "27.5.1"
"jest": "26.4.2" -> "27.5.1"
+ "jest-environment-jsdom": "27.5.1"
- "vue-jest": "3.0.7"
+ "vue3-jest": "27.0.0-alpha.1"
Error & Warning
Module not found: Error: Can't resolve 'vue' in ...
vue2更新为vue3的初始,需要引入@vue/compat
作为桥梁。
在webpack.conf.js中,加入:
alias: {
'vue': '@vue/compat'
}
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
compilerOptions: {
compatConfig: {
MODE: 2
}
}
}
},
.....
注:全部替换结束后,最好移除@vue/compat
,结束兼容模式。
Vue packages version mismatch: vue & vue-template-compiler
vue 3已经不再使用vue-template-compiler
,而是改为使用@vue/compiler-sfc
但是,移除之后会造成新的error:
[vue-loader] vue-template-compiler must be installed as a peer dependency, or a compatible compiler implementation must be passed via options.
解决方法是升级vue-loader到^v17
sass-loader > this.getOptions is not a function
那就先不要升级sass loader啊!!!
高级别的sass-loader:minimum supported webpack version is 5!
vue-rouder > Can't import the named export 'computed' from non EcmaScript module (only default export is available)
为mjs文件加入新规则:
{
test: /\.mjs$/,
include: /node_modules/,
type: "javascript/auto"
}
vue-router > Cannot read properties of null (reading 'parent')
Uncaught TypeError: Cannot read properties of null (reading 'parent')
at warnDeprecatedUsage (vue-router.mjs?6605:2457:1)
这个bug有毒吧!!!!!
只要先mount vueApp,再use(router)就好了!!!
搞了半天!!!无能咆哮!!!
但是顺序一搞,又来一个新的warningFailed to resolve component: [router-view]
所以这个solution是错的啊啊啊!!!还是要先use再mount啊!!!
最后的solution居然是!!!把vue-router的版本从4.1降到4.0.6!!!
4.0.6
!!!
业务代码重构
gogocode
npm install gogocode-cli
sudo gogocode -s ./src -t gogocode-plugin-vue -o ./src-out // v2 -> v3
gogocode -s ./src-out -t gogocode-plugin-element -o ./src-out1 // element-UI -> element-Plus
断开所有router和UI引用,逐个文件进行修改替换。
最后记得移除package.json里的gogocode
重要改动
在vuex中引用vue实例
vue2: this._vm
vue3: 需要在引入组件的时候,传入vueApp
如:需要在vuex中使用全局的$api
main.js:
import { createStore } from './store/store.js'
import ApiPlugin from './request/api/api.js'
const store = createStore(vueApp)
vueApp.use(store)
store.js:
import { createStore as createVuexStore } from 'vuex'
export const createStore = (vueApp) => {
return createVuexStore({
modules: {
moduleA: ModuleA(vueApp),
},
})
}
moduleA.js:
export default (vueApp) => {
const _vm = vueApp.config.globalProperties
return {
...
actions: {
func () {
_vm.$api.funcName()...
}
}
}
Error & Warning
升级素材库
element-UI
升级为element-Plus
可以通过gogocode来转换代码。但必须人工校验!!!(实际上我对比了前后的code,似乎好像可能没有什么改动……)
参考# Element Plus Breaking Changes
其中,icon的引用是较大的改动,需要逐个修改。其他的组件,对照link中的表格一一对应替换调整即可。
icon
v2: <el-button icon="search">
& <el-button icon="fa fa-save">
v3:
对于el-icon:<el-button :icon="Search">
其中Search为引入的icon component.
引入其他icon:<el-button><i class="fa fa-save"></i></el-button>
引用单组建
当单个组建引用时,注意组建名的改变。如
v2:import { Message } from 'element-ui'
v3:import { ElMessage } from 'element-plus'
样式微调
配色: 采用use的方式引入,适用于较多组件样式都需要修改的情形。对于只需要调整主题色的情形,只修改var比较方便。
//element-variables.scss:
:root {
--el-color-primary: green;
--el-color-primary-light-3: #7cb718;
--el-color-primary-light-5: #97c941;
--el-color-primary-light-7: #a8ce66;
--el-color-primary-light-8: #d0e4ad;
--el-color-primary-light-9: #f8feed;
--el-color-primary-dark-2: darkGreen;
}
在main.js中引入:
import ElementPlus from 'element-plus'
import 'element-plus/theme-chalk/src/index.scss'
import './styles/element-variables.scss'
可能需要单独调整的样式:
.el-submenu中的hover的背景色
.el-menu--popup-right-star的margin,即子目录的显示位置
.el-dialog__headerbtn的close btn位置
vue-form-json-schema
使用vue-form-json-schema@3.0.0-alpha.0
vue3-form-json-schema根本不能用!
升级版本之后,需要有以下改动:
- el-row和el-col不再自动转为div,需要手动处理span和offset
- el-input不再自动转为div。需要手动设置type=number的形式的class。
- el-icon设置class不再生效,需要重新引入。
- el-button和el-icon的click事件不再生效,需要额外定义。
- el-checkbox
- el-select / el-option全部平铺显示,组件引用方法改变。改使用HTML中的select和options。
-
- multiple需要另外设计 -> 哭了啊html的multiple select行为是什么鬼!
-
- remote需要另外设计
因为对element-plus不支持,且alpha版本不稳定,所以迟早要替换它。
el-select
- 创建option children,包括绑定onClick事件。使用
<ul>
和<li>
- 创建selection component
-
第一层div,绑定onClick事件,触发点击时展开dropdown-list
-
第二层div,input wrapper,注入input外层的class
-
第三层,包括input,dropdownComponent,suffix icon。
- 处理isMultiple,包括鼠标事件冒泡和值回传,还有高度自适应。
- 处理remote,提前fetch取值,完成后eventBus触发刷新回流。
- 处理label,不显示原始value,显示可读的label。
很!麻!烦!而且不!好!用!
所以!!!前面的都是错的!!!
最后,真正的解决方法:
<vue-form-json-schema
:components="components"
/>
import { shallowRef } from 'vue'
import {
ElButton, ElSelect, ElOption, ElInput, ElCheckbox, ElTooltip, ElTag,
ElSelectTag, ElIcon, ElFormItem, ElOptionGroup
} from 'element-plus'
data () {
return {
components: {
'el-button': shallowRef(ElButton),
'el-icon': shallowRef(ElIcon),
'el-select': shallowRef(ElSelect),
'el-option': shallowRef(ElOption),
'el-input': shallowRef(ElInput),
'el-checkbox': shallowRef(ElCheckbox),
'el-tooltip': shallowRef(ElTooltip),
'el-tag': shallowRef(ElTag),
'el-select-tag': shallowRef(ElSelectTag),
'el-form-item': shallowRef(ElFormItem),
'el-option-group': shallowRef(ElOptionGroup)
},
vue-code-diff
直接转为v-code-diff,丝滑~ # v-code-diff,一个 vue2/3 可用、更多特性支持的代码对比插件
vue-js-modal
vue3不支持了!!!考虑换组件!!!
Error & Warning
Extraneous non-props attributes (class) were passed to component
对于el-dialog,不应该el-dialog层传入id和class。
unit test
升级module
- Vue Test Utils 1 targets Vue 2.
- Vue Test Utils 2 targets Vue 3.
vuex传入vueApp参数
由于需要在store中使用vm,所以需要在store引入vueApp。(详见 ### 在vuex中引用vue实例)
在unit test中,也需要进行引用。
import { createStore } from 'vuex'
...
const store = (vueApp) => {
vueApp.config.globalProperties.$store = createStore({
modules: {
MODULEA: cloneDeep(MODULEA(vueApp)),
}
})
}
...
wrapper = mount(App, {
global: {
plugins: [store]
}
}
wrapper.text拿不到东西
打出wrapper.html()发现,由于Element-Plus的dropdown是默认插入到Body层的,导致HTML导出为:
...
<!--teleport start-->
<!--teleport end-->
...
需要把el-dropdown设置:teleported="false"
wrapper.vm为空{}
mount之后,获取wrapper.vm,console出来是空的。
检查发现是因为vue文件中使用了setup。
setMethod不再支持
直接在mount之后赋值。
wrapper.vm.initJsonEditor = () => {
console.log('debug ==> mock init')
jest.fn()
}
test router
before:expect(router.currentRoute._value.query.tab).toBe('components')
afterexpect(router.history.current.query.tab).toBe('components')
Error & Warning
Cannot find module 'vue-template-compiler
babelJest.getCacheKey is not a function
Cannot read properties of undefined (reading 'testEnvironmentOptions')
以上都是jest相关版本问题!!!
vue3-jest,jest,vue/unit-test,babel-jest都需要安装到互相适配的版本上!!!巨坑!!!
feat: support jest v27 in vue3-jest #343
还有一些break changes: # Migrating from Vue Test Utils v1
一个巨坑
如果webpack在打包过程中,不打包vuex的话,会导致vuex中的值无法更新!!!可能跟reactive机制相关!!!
耗时记录
project 1: vue 2.6.12 & vuex 3.6.2 & webpack 4 & element-UI
2023/3/13 开始知识调研 & 环境替换
2023/3/16 开始代码调整
2023/3/20 element-UI -> element-plus 1d
2023/3/21 vue-form-json-schema 修改component形式
2023/3/29 升级unit test环境,修改test代码
2023/4/4 上传到staging server并测试
2023/4 部署到production server
2023/4 处理非block的一系列改动。
- 彻底替换vue-form-json-schema
- 替换butterfly
- 替换eventBus
- 使用composition API优化代码
- 移除构建版本
project 2: vue 2.6.14 & vuex 3.6.2 @ webpack 4 & electron 13.6.9
2023/4/18 开始环境替换