记一次老项目升级到 Vue2.7 的踩坑记录
前段时间把公司的一个老项目框架升级到了 Vue2.7,期间也是踩了一些坑,简单记录一下供大家参考。
先放一个官方迁移文档地址
为什么要升级Vue2.7?
- 统一Vue2与Vue3的写法从而方便已有项目的迁移或重构
- 方便抽离hooks从而获得更好的开发体验
升级步骤
一、vue-cli 相关的包
涉及范围:
"@vue/cli-plugin-babel": "~4.5.18",
"@vue/cli-plugin-eslint": "~4.5.18",
"@vue/cli-plugin-router": "~4.5.18",
"@vue/cli-plugin-unit-jest": "~4.5.18",
"@vue/cli-plugin-vuex": "~4.5.18",
"@vue/cli-service": "~4.5.18",
本来想尝试将脚手架升级到5.x
,但无奈 webpack5
有很多 breaking changes, 常用的 loader 和 plugin 都有大版本变更,改起来实在有心无力,所以退而求次只升级到4.x
的最新版本。
二、vue 相关的包
涉及范围:
"vue": "^2.7.13",
"vue-router": "~3.6.5",
"vuex": "~3.6.2",
// 2.7 版本不再需要 vue-template-compile,可以移除
--"vue-template-compiler": "^2.6.11",
除了要将 vue
的版本升至2.7
以外还要将 vuex
和 vue-router
升级至3.x
的最新版本。主要是为了兼容 composition-api
<script setup>
import { useRouter } from 'vue-router/composables'
const router = useRouter()
</script>
vuex
并没有提供 useStore
方法,建议开发新功能时使用 pinia
而不是 vuex
三、eslint 相关的包
涉及范围:
"babel-eslint": "^10.1.0",
"eslint": "~7.32.0",
"eslint-plugin-vue": "~9.9.0",
项目中原先使用的是 eslint@6.7.2
,此版本不支持可选链运算符,所以需要升级,至于为什么不升到最新版本,后面踩坑记录会解释。
babel-eslint
实际上已经弃用了,现在应该使用 @babel/eslint-parser
,但盲目升级容易踩大坑,所以暂时将其升至弃用前的最新版本,等后续重构项目时再进行升级。
因为 vue2.7
支持 <script setup>
语法,所以要将 eslint-plugin-vue
升至9.x
,也就是支持 vue3.x
的版本,否则 eslint
会报 no-unused-vars
的错误。
此外,本次升级还修改了部分 .eslintrc.js
配置,代码如下:
module.exports = {
root: true,
env: {
node: true,
es6: true,
},
extends: ['plugin:vue/essential', 'eslint:recommended', 'plugin:prettier/recommended'],
plugins: ['prettier'],
parser: 'vue-eslint-parser',
parserOptions: {
ecmaVersion: 2020,
parser: 'babel-eslint',
sourceType: 'module',
},
rules: {
'prettier/prettier': ['error'],
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'vue/multi-word-component-names': 'off',
'vue/no-reserved-component-names': 'off',
'no-unused-vars': 'warn',
},
}
四、sass相关的包
涉及范围:
"node-sass": "^6.0.1",
"sass-loader": "^10.2.1",
项目中原先使用的是 sass-loader@8.0.2
,webpack4
最高可支持版本是10.x
,所以进行升级。
实际上 sass-loader
从9.x
开始就推荐使用 dart-sass
来替代 node-sass
,但由于项目中很多地方使用了 /deep/
的写法,导致 dart-sass
解析不通过,所以暂时还是使用 node-sass
,并将其升级到 sass-loader@10.x
所需的6.x
版本。
五、集成windicss
最简单的一个步骤:vue add windicss
官方文档:windicss.org/integration…
踩坑总结
一、集成unplugin-auto-import
最开始的时候,我倾向于将 unplugin-auto-import 集成到项目中,毕竟在每个文件内手动导入 vue 的各种 API 确实有点麻烦。集成之后插件确实起作用了,不需要 import 就可以直接写 ref 也确实很舒适,但是 volar
的 Auto Complete Refs
功能失效了(盲猜是 vue2.7
的原因),并且考虑到项目是团队协作开发,外部的东西有明确的来源才能更好地让其他人理解代码。于是最后还是决定移除 unplugin-auto-import
二、使用相对路径引用的图片解析后的地址不正确
项目中有一些图片是在 css 中使用相对路径引用的,比如:
.icon2front {
z-index: 2;
transform: rotateY(0deg);
background-image: url('../../images/home-SZJX-icon2.png');
}
启动服务后类似这种相对路径引用的图片全都无法显示,而引用自 public
文件夹下的静态资源则没有问题。
打开控制台可以看到,使用相对路径的图片打包后的路径变成了 background-image: url(img/home-SZJX-icon2-sel.dea0b320.png);
,很明显是引用路径不对,正确的引用应该基于当前的文件路径 url(/img/home-SZJX-icon2-sel.dea0b320.png)
一顿乱七八糟的分析之后,发现问题应该是处在 url-loader
上,在 vue.config.js
中给 url-loader
配置了 publicPath = '/'
成功解决问题。
三、启动项目时报错TypeError: this.cliEngine is not a constructor
这个就是前面提到的关于 eslint@8.x
的坑了。
原因是项目中使用了 vue-eslint-parser
作为 eslint
的 parser,而 vue-eslint-parser
最高仅支持 eslint@7.x
,所以才会报错,将 eslint
降为7.x
版本即可解决问题。
四、引入windicss后启动服务报错
启动项目后报 Syntax Error: Unterminated string constant
,报错代码如下:
// import { replace } from 'lodsh-es'
return replace(
this.content,
'<body',
'<style type="text/css">body {user-select: none;}</style><body'
)
看上去是把 js 代码中的 html 片段一起解析了,解决方法是使用模板字符串进行换行:
return replace(
this.content,
'<body',
`<style type="text/css">
body {user-select: none;}
</style>
<body`
)
五、引入windicss后首页样式不正确
原因是出在样式类名上,项目的首页自定义了一个叫做 container
的样式类,恰巧 windicss
中预设了一个 shortcuts 也叫 container
,于是 windicss
的样式就被 merge 进了项目里的自定义类,导致首页的样式不正确。解决方法是在 windicss.config.js
中配置一个 shortcuts 来覆盖掉预设:
import { defineConfig } from 'windicss/helpers'
export default defineConfig({
preflight: false,
plugins: [
require('windicss/plugin/filters'),
require('windicss/plugin/forms'),
require('windicss/plugin/aspect-ratio'),
require('windicss/plugin/line-clamp'),
require('windicss/plugin/typography')({
modifiers: ['DEFAULT', 'sm', 'lg'],
}),
],
shortcuts: {
// 覆盖自带的shortcuts
container: '',
},
})
六、Jenkins打包报错
① npm install
失败
原因:Jenkins 上的 Node
版本使用的是16.x
,npm
版本则是8.x
,项目依赖冲突导致安装过程中断,解决方法是给 npm install
加上后缀 --legacy-peer-deps
,详细原理可参考这篇文章
② SyntaxError: Unexpected token u in JSON at position 0 vue.config.js
原因:项目中的 vue.config.js
使用了 process.env.npm_config_argv
全局变量,但这个变量从 npm@7.x
开始就被移除了。解决方法是将命令改为 npm run <command> -- --param=value
并使用 process.argv
来获取命令参数。但由于项目中并没有实际使用该变量(process.env.npm_config_argv
),所以只是将其注释掉,并没有进行其他更改。
总结
这次升级确实花了不少时间,时间长的原因:
- 各种小坑太多,以上列出的几个坑只是比较突出,实际上还有很多其他的坑会踩到。
- 需要做的取舍太多,来来回回试了好几种方案,其中
unocss
消耗的时间最长,可惜最终还是没能用上(项目自身的问题)。 - 自身技术水平不够扎实,很多
webpack
的配置要查很久。 - 一开始没有做好规划,直接就上手改了,越改越乱,导致花费的时间暴涨。
转载自:https://juejin.cn/post/7233261440501055547