什么是 Vite+(vp)
Vite+ 是 VoidZero 推出的统一 Web 工具链,把 Vite、Vitest、Oxlint、Rolldown、tsdown 集成到一个 vp 命令里。Node.js 版本管理、包管理器检测、dev/build/test 全部通过 vp 统一入口,不需要分别装多个工具。
# 安装(Linux / macOS)
curl -fsSL https://vite.plus | bash
# 验证
vp --version
1. 创建项目
vp create vue 底层调用 create-vue,支持交互式选项,一次性把 TypeScript、Pinia、Vue Router 全勾上:
# 交互式(推荐,会问你要不要 TS/Router/Pinia 等)
vp create vue
# 非交互式(全部选 yes,直接得到完整骨架)
vp create vue -- --ts --router --pinia --eslint --default
create-vue 生成的目录结构:
my-app/
├── src/
│ ├── assets/
│ ├── components/
│ ├── router/
│ │ └── index.ts ← 已生成
│ ├── stores/
│ │ └── counter.ts ← 已生成
│ ├── views/
│ ├── App.vue
│ └── main.ts
├── vite.config.ts
└── tsconfig.json
2. 安装依赖
vp install 会自动检测项目里用的是 pnpm/bun/npm/yarn,无需手动指定:
cd my-app
vp install
# 追加 Element Plus
vp install element-plus @element-plus/icons-vue
vp install -D unplugin-auto-import unplugin-vue-components
3. Element Plus 按需导入
修改 vite.config.ts:
// vite.config.ts
import { defineConfig } from 'vite-plus' // ← 用 vite-plus 的 defineConfig
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
export default defineConfig({
plugins: [
vue(),
// 自动导入 Vue/Vue Router/Pinia Composition API,无需手写 import
AutoImport({
imports: ['vue', 'vue-router', 'pinia'],
resolvers: [ElementPlusResolver()],
dts: 'src/auto-imports.d.ts',
}),
// 自动按需导入 Element Plus 组件
Components({
resolvers: [ElementPlusResolver()],
dts: 'src/components.d.ts',
}),
],
resolve: {
alias: { '@': '/src' },
},
})
为什么用
vite-plus的defineConfig而不是vite?vite-plusre-export 了 Vite 所有 API,同时扩展了test/lint/fmt等字段。两者兼容,项目迁移零成本。
⚠️ Element Plus 样式丢失
按需导入不会自动引入全局 CSS,在 main.ts 加一行兜底:
import 'element-plus/dist/index.css'
4. Pinia Store
Composition API 风格(推荐,类型推断最好):
// src/stores/user.ts
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', () => {
const token = ref(localStorage.getItem('token') ?? '')
const name = ref('')
const isLoggedIn = computed(() => !!token.value)
function login(t: string, n: string) {
token.value = t
name.value = n
localStorage.setItem('token', t)
}
function logout() {
token.value = ''
name.value = ''
localStorage.removeItem('token')
}
return { token, name, isLoggedIn, login, logout }
})
5. Vue Router
// src/router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{ path: '/', redirect: '/home' },
{
path: '/home',
component: () => import('@/views/HomeView.vue'),
meta: { title: '首页', requiresAuth: false },
},
{
path: '/dashboard',
component: () => import('@/views/DashboardView.vue'),
meta: { title: '控制台', requiresAuth: true },
},
{
path: '/:pathMatch(.*)*',
component: () => import('@/views/NotFoundView.vue'),
},
],
scrollBehavior: (_, __, saved) => saved ?? { top: 0 },
})
// 路由守卫
router.beforeEach((to, _, next) => {
// ✅ 在守卫内部调用 store,pinia 此时已经通过 app.use(pinia) 激活
const userStore = useUserStore()
document.title = (to.meta.title as string) ?? '应用'
if (to.meta.requiresAuth && !userStore.isLoggedIn) {
next({ path: '/login', query: { redirect: to.fullPath } })
} else {
next()
}
})
export default router
⚠️ 守卫里用 Pinia 的正确姿势
必须在守卫函数内部调用 useXxxStore(),不能在模块顶层调用——那时 app.use(pinia) 还没执行,会报 getActivePinia was called with no active Pinia。
6. main.ts 完整写法
// src/main.ts
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
import 'element-plus/dist/index.css'
import * as Icons from '@element-plus/icons-vue'
const app = createApp(App)
// pinia 必须在 router 之前注册,路由守卫才能正常使用 store
app.use(createPinia())
app.use(router)
// 全局注册 Element Plus 图标
Object.entries(Icons).forEach(([k, v]) => app.component(k, v))
app.mount('#app')
7. 日常开发命令(全用 vp)
vp dev # 启动开发服务器(Vite HMR)
vp build # 生产构建(Rolldown)
vp check # lint + type-check + format 三合一
vp test # 运行 Vitest 测试
vp install # 安装依赖(自动检测包管理器)
常见坑速查
| 问题 | 原因 | 解法 |
|---|---|---|
| Element Plus 无样式 | 按需导入未引入全局 CSS | import 'element-plus/dist/index.css' |
| Pinia 守卫报错 | 模块顶层调用 store,pinia 未激活 | 守卫函数内部调用 useXxxStore() |
| TS 找不到组件类型 | components.d.ts 未加入 tsconfig | 加进 include |
vp 命令找不到 | PATH 未配置 | source ~/.bashrc 或重开终端 |