由于项目使用ElementUI组件库二次封装&样式重置,加上庞大的shit山代码,升级到Vue3时间方面&技术不可行,所以为了使用新特性的同时保证项目的相对稳定性,决定将Vue版本升级到2.7版本,同时将Vue-cli重构为Vite,加快启动&打包速度。
1、将Vue-cli升级到4版本
"@vue/cli-plugin-babel": "^4.5.18",
"@vue/cli-service": "^4.5.18",
2、将Vue升级到2.7版本
"vue": "^2.7.16",
3、将vue-i18n升级或者去除
由于项目使用vue-i18n实现国际化,因为版本不兼容,所以需要升级或者按需去除
4、将项目中的/deep/或者::v-deep改成:deep()
我这边更改后不生效,所以我没管(狗头)
5、安装Vite及插件
"vite": "^4.5.5",
"vite-plugin-env-compatible": "^2.0.1",
"vite-plugin-html": "^3.2.2",
"@vitejs/plugin-vue2": "^2.3.1",
"@originjs/vite-plugin-commonjs": "^1.0.3",
新建vite.config.js,引入插件
// 环境变量兼容处理,比如vite只识别VITE开头的环境变量,而我们要兼容vuecli中以VUE_APP开头的
// 同时需要在defineConfig中配置envPrefix: ['VUE_APP_']
import envCompatible from 'vite-plugin-env-compatible'
// 因为vite仅支持esm,所以使用这个插件将项目中如require/modules.export等commonjs语法转换为esm
import { viteCommonjs } from '@originjs/vite-plugin-commonjs'
// 使Vue2支持Vite的插件
import vue from '@vitejs/plugin-vue2'
...
plugins: [
envCompatible(),
viteCommonjs(),
vue()
],
6、配置vite.config.js
按照你之前的wepack.config.js或vue.config.js配置迁移过去即可,注意细微差异,如Vite天然支持sass、less、typescript,只需要下载依赖不需要额外配置rules即可使用。
一些webpack特有的配置如chainWebpack、configureWebpack要使用vite配置项重构,由于Vite打包底层是Rollup,所以更多自定义配置可以在 build.rollupOptions 中自行配置。
7、将commonjs转换为esm
刚刚下载的@originjs/vite-plugin-commonjs已经可以帮你将打包产物转成esm了,但是可能node_modules中有些第三方包也是cjs,所以需要在build配置项配置commonjs的选项
build: {
commonjsOptions: {
// node_modules中有的包也是commonjs格式,需要开启第三方包cjs模块转换
transformMixedEsModules: true
},
}
另外如path.resolve等node模块方法也不允许使用,你可以安装插件实现或者自行实现;
比如我自行实现的path.resolve方法:
export function resolvePathFn(basePath, relativePath) {
// 将路径分割成段
const baseSegments = basePath.replace(/^\/|\/$/g, '').split('/')
const relativeSegments = relativePath.replace(/^\/|\/$/g, '').split('/')
// 合并路径段并去重
const allSegments = [...baseSegments]
for (const segment of relativeSegments) {
if (segment === '..') {
allSegments.pop()
}
else if (segment !== '.' && segment !== '' && !allSegments.includes(segment)) {
allSegments.push(segment)
}
}
return '/' + allSegments.join('/')
}
还有如果用到require.context获取模块信息可以改成:
import.meta.glob('./modules/**/*.js', { eager: true })
使用require引入的图片等资源改成import直接引入即可,包括:
// 如路由懒加载的
(resolve) => require(xxx).then(resolve)
// 改成
() => import(xxx)
此时打包就不会出现require is not defined等cjs方面报错了。
8、引入TypeScript
下载依赖
"typescript": "^5.7.2",
新建tsconfig.json配置文件,常用配置如下,具体可以查阅ts官网。
{
"compilerOptions": {
"forceConsistentCasingInFileNames": true,
"target": "esnext",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node",
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"baseUrl": ".",
"outDir": "./dist",
"types": [
"node",
"vue",
],
"paths": {
"@/*": ["./src/*"]
},
"lib": ["esnext", "dom", "dom.iterable", "scripthost"]
},
"include": ["**/*.ts", "**/*.tsx", "**/*.vue"],
"exclude": ["node_modules", "mock", "build", "dist"],
"vueCompilerOptions": {
"extensions": [
".vue"
],
"target": 2.7
}
}
9、测试重构效果是否生效
新建types/userInfo.d.ts文件测试声明ts类型
type UserInfo = {
name: string
age: number
}
新建test.vue文件,写入composition api + ts 代码
<script setup lang="ts">
import { onMounted, reactive, ref } from 'vue';
const count = ref<number>(0)
const increment: Fn<void, void> = () => {
count.value++
}
const user = reactive<UserInfo>({
name: 'ouzx',
age: 25
})
const handleChangeUserName = (): void => {
user.name = 'ouzx' + Math.random()
}
const handleChangeUserAge = (): void => {
user.age += 1
}
onMounted(() => {
alert('调用onMounted钩子')
})
</script>
<template>
<div>
<p>计数器:{{ count }}</p>
<el-button @click="increment">点我加一</el-button>
<br/><br/>
<p>名字:{{ user.name }}</p>
<br/><br/>
<el-button @click="handleChangeUserName">点我改名</el-button>
<br/><br/>
<p>年龄:{{ user.age }}</p>
<el-button @click="handleChangeUserAge">点我改年龄</el-button>
</div>
</template>
在package.json配置运行/打包命令并执行
"scripts": {
"serve": "vite",
"build": "vite build"
},
开发/生产环境均可成功运行。
10、总结
1、升级到Vue2.7 / VueCli4版本
2、下载Vite及插件
3、将VueCli配置转为Vite配置
4、将commonjs转换为esm
5、引入TypeScript并编写配置文件