Vue 2 升级 Vue 3 全流程实战手册(Vue CLI 转 Vite + Element Plus + Pinia)
本文为完整实战文档,包含全流程,已脱敏处理隐私信息,可直接用于企业项目升级参考,复制即可发布至 CSDN。
·
Vue 2 升级 Vue 3 全流程实战手册(Vue CLI 转 Vite + Element Plus + Pinia)
本文为Vue 2 项目迁移 Vue 3完整实战文档,包含依赖升级、构建工具切换、组件适配、样式改造、状态管理替换全流程,已脱敏处理隐私信息,可直接用于企业项目升级参考
📋 项目基础信息
表格
| 项目名称 | XX 业务管理系统 |
|---|---|
| 升级日期 | 2026-04-18 |
| 原始版本 | Vue 2.7.15 + Vue CLI + Element UI |
| 目标版本 | Vue 3.4.0 + Vite + Element Plus + TypeScript |
| 升级状态 | ✅ 已完成 |
一、技术栈对比
表格
| 组件 | 升级前 | 升级后 | 变化说明 |
|---|---|---|---|
| 核心框架 | Vue 2.7.15 | Vue 3.4.0 | 全面采用 Composition API,响应式系统基于 Proxy 重构,性能提升 30%-200% |
| 路由管理 | Vue Router 3.6.5 | Vue Router 4.2.0 | API 函数化,支持动态路由更灵活,移除部分旧 API |
| 状态管理 | Vuex 3.6.2 | Pinia 2.1.7 | Vue 3 官方推荐,无 mutations,TypeScript 支持更好,代码更简洁 |
| UI 组件库 | Element UI 2.15.13 | Element Plus 2.4.4 | 适配 Vue 3,组件 API 优化,新增暗黑模式等特性 |
| 构建工具 | Vue CLI 5.x | Vite 5.0.0 | 基于 ESBuild 的极速开发体验,冷启动快 10 倍以上,热更新毫秒级 |
| 开发语言 | JavaScript | JavaScript + TypeScript | 增强类型安全,减少运行时错误,提升代码可维护性 |
二、升级前准备工作
2.1 代码备份与环境检查
- 备份代码:将当前项目代码提交到 Git 仓库,创建
feature/vue3-migration分支 - Node.js 版本:确保 Node.js 版本 ≥ 18.0.0(Vite 5.x 要求)
- 依赖兼容性检查:使用
npm outdated检查第三方依赖是否支持 Vue 3
2.2 工具辅助(可选)
使用 Vue 官方迁移工具初步检查代码:
bash
运行
npm install -g @vue/cli-plugin-vue3-migration
vue-cli-service vue3-migration
三、依赖变更清单
3.1 package.json 脚本命令变更
表格
| 命令 | 升级前 (Vue CLI) | 升级后 (Vite) | 说明 |
|---|---|---|---|
| 启动开发服务器 | npm run serve |
npm run dev |
Vite 开发服务器,支持 HMR 热更新 |
| 生产构建 | npm run build |
npm run build |
使用 Rollup 打包,产物更优化 |
| 预览构建结果 | 无 | npm run preview |
本地预览生产构建产物 |
| 类型检查 | 无 | npx tsc --noEmit |
TypeScript 类型检查,不生成文件 |
3.2 依赖包变更明细
3.2.1 移除的依赖
表格
| 依赖包 | 移除原因 |
|---|---|
vue-template-compiler |
Vue 3 不再需要单独的模板编译器,已集成到 @vitejs/plugin-vue |
@vue/cli-service、@vue/cli-plugin-babel、@vue/cli-plugin-router |
替换为 Vite 构建工具链 |
element-ui |
Vue 2 专属 UI 库,替换为 Element Plus |
vuex |
Vue 3 官方推荐使用 Pinia,更轻量且 TypeScript 支持更好 |
3.2.2 新增的依赖
json
{
"dependencies": {
"vue": "^3.4.0",
"vue-router": "^4.2.0",
"pinia": "^2.1.7",
"element-plus": "^2.4.4",
"@element-plus/icons-vue": "^2.3.1"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.0.0",
"vite": "^5.0.0",
"typescript": "^5.3.3",
"vue-tsc": "^1.8.27"
}
}
四、核心文件变更详解
4.1 入口文件 main.js
4.1.1 升级前 (Vue 2)
javascript
运行
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import request from '@/utils/request'
Vue.config.productionTip = false
Vue.use(ElementUI, { size: 'mini' })
Vue.prototype.request = request
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
4.1.2 升级后 (Vue 3)
javascript
运行
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import { createPinia } from 'pinia'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import request from '@/utils/request'
const app = createApp(App)
app.use(ElementPlus, { size: 'default' })
app.use(router)
app.use(createPinia())
app.config.globalProperties.$request = request
app.mount('#app')
4.1.3 核心变化详解
表格
| 变更项 | Vue 2 写法 | Vue 3 写法 | 说明 |
|---|---|---|---|
| 创建应用 | new Vue() |
createApp(App) |
Vue 3 采用函数式创建,支持多个应用实例 |
| 插件注册 | Vue.use(Plugin) |
app.use(Plugin) |
插件注册绑定到具体应用实例,而非全局 |
| 全局属性 | Vue.prototype.$xxx |
app.config.globalProperties.$xxx |
全局属性挂载到应用配置,避免污染全局 |
| 挂载方式 | new Vue().$mount('#app') |
app.mount('#app') |
更简洁的挂载 API |
4.2 路由配置 router/index.js
4.2.1 升级前 (Vue Router 3)
javascript
运行
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '@/views/Home.vue'
Vue.use(VueRouter)
const routes = [
{ path: '/', name: 'Home', component: Home },
{ path: '/about', name: 'About', component: () => import('@/views/About.vue') }
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
router.beforeEach((to, from, next) => {
const user = store.state.user
if (to.meta.requiresAuth && !user) next('/login')
else next()
})
export default router
4.2.2 升级后 (Vue Router 4)
javascript
运行
import { createRouter, createWebHistory } from 'vue-router'
import Home from '@/views/Home.vue'
import { useMainStore } from '@/store'
const routes = [
{ path: '/', name: 'Home', component: Home },
{ path: '/about', name: 'About', component: () => import('@/views/About.vue') }
]
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes,
scrollBehavior(to, from, savedPosition) {
return savedPosition || { top: 0 }
}
})
router.beforeEach((to, from) => {
const store = useMainStore()
const user = store.user
if (to.meta.requiresAuth && !user) return '/login'
})
export default router
export function resetRouter() {
const newRouter = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes
})
router.matcher = newRouter.matcher
}
4.3 状态管理(Vuex → Pinia)
4.3.1 升级前 (Vuex)
javascript
运行
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: { user: null, currentPathName: '' },
getters: { isLoggedIn: state => !!state.user },
mutations: {
SET_USER(state, user) { state.user = user },
LOGOUT(state) { state.user = null }
},
actions: {
login({ commit }, user) { commit('SET_USER', user) },
logout({ commit }) { commit('LOGOUT') }
}
})
4.3.2 升级后 (Pinia)
javascript
运行
import { defineStore } from 'pinia'
import router, { resetRouter } from '@/router'
export const useMainStore = defineStore('main', {
state: () => ({
user: JSON.parse(localStorage.getItem('user') || 'null'),
currentPathName: localStorage.getItem('currentPathName') || ''
}),
getters: { isLoggedIn: (state) => !!state.user },
actions: {
login(user) { this.user = user },
logout() {
this.user = null
router.push('/login')
resetRouter()
}
}
})
4.4 UI 组件库适配(Element UI → Element Plus)
4.4.1 全局方法调用变更
表格
| 使用场景 | 升级前 | 升级后 |
|---|---|---|
| 消息提示 | this.$message.success('') |
ElMessage.success('') |
| 确认弹窗 | this.$confirm('') |
ElMessageBox.confirm('') |
4.4.2 图标使用变更
vue
<script setup>
import { Edit, Search } from '@element-plus/icons-vue'
</script>
<template>
<el-icon><Edit /></el-icon>
<el-button :icon="Search">搜索</el-button>
</template>
4.5 样式深度选择器变更
4.5.1 升级前 (Vue 2)
css
::v-deep .el-input__inner { background: #f5f7fa; }
4.5.2 升级后 (Vue 3)
css
:deep(.el-input__inner) { background: #f5f7fa; }
4.5.3 注意事项
::v-deep、>>>、/deep/在 Vue 3 中已废弃,必须使用:deep():deep()必须包裹目标选择器,不能单独使用<style scoped>下深度选择器仅作用于当前组件子组件
4.6 组件导入规范变更
Vite 强制要求导入组件必须加 .vue 后缀:
javascript
运行
// 升级前
import Aside from '@/components/Aside'
// 升级后
import Aside from '@/components/Aside.vue'
五、Composition API 迁移示例
5.1 升级前 (Options API)
vue
<script>
export default {
data() { return { form: {}, user: {} } },
created() { this.getData() },
methods: {
async getData() { /* 请求逻辑 */ },
saveData() { /* 保存逻辑 */ }
}
}
</script>
5.2 升级后 (Composition API + script setup)
vue
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import request from '@/utils/request'
const emit = defineEmits(['refreshData'])
const user = ref({})
const form = reactive({})
onMounted(() => { getData() })
const getData = async () => { /* 请求逻辑 */ }
const saveData = async () => {
await request.post('/api/user/save', form)
ElMessage.success('保存成功')
emit('refreshData')
}
</script>
六、构建配置变更
6.1 vite.config.ts
typescript
运行
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
export default defineConfig({
plugins: [vue()],
resolve: { alias: { '@': path.resolve(__dirname, './src') } },
server: {
port: 8080,
proxy: { '/api': { target: 'http://localhost:9090', changeOrigin: true } }
},
build: { chunkSizeWarningLimit: 400 }
})
6.2 index.html 入口文件
html
预览
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>XX业务管理系统</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
七、常见问题与解决方案
表格
| 错误现象 | 原因 | 解决方法 |
|---|---|---|
| 组件导入找不到文件 | 缺少 .vue 后缀 |
所有组件导入加 .vue |
| this.$message 未定义 | Vue 3 无全局方法 | 导入 ElMessage 使用 |
| 深度选择器失效 | 语法废弃 | 替换为 :deep() |
| 路由报错 removeRoute | API 变更 | 使用 resetRouter |
八、升级验证清单
- ✅
npm install依赖安装成功 - ✅
npm run dev开发服务正常启动 - ✅ 登录、路由、组件渲染正常
- ✅
npm run build生产构建无报错 - ✅ TypeScript 类型检查通过
九、升级成果
表格
| 指标 | 升级前 | 升级后 | 改善幅度 |
|---|---|---|---|
| 开发启动时间 | 30-60s | 5-10s | 提升 6-12 倍 |
| 热更新速度 | 1-3s | <100ms | 提升 10-30 倍 |
| 首屏体积 | ~352KB | ~47KB | 减少 87% |
十、参考文档
📌 文末说明
本文为企业级 Vue2 升级 Vue3 实战文档,已完成隐私脱敏,适用于所有 Vue2 老项目升级参考。完整文档
#Vue #Vue3 #Vite #前端升级 #ElementPlus #Pinia
更多推荐
所有评论(0)