记一次老项目升级到 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