


Vue 3 + Vite 前端项目实践指南 适用版本(截至 2026 年 7 月):Vue 3.5+ | Vite 6/7 | TypeScript 5.6+ | Node.js ^20.19.0 || >=22.12.0 目标:从零搭建一个可投入生产的工程化项目,覆盖「初始化 → 架构 → 规范 → 联调 → 构建部署」全流程。 全景路线图 环境准备 ──▶ 脚手架创建 ──▶ 目录规划 ──▶ Vite 配置 ──▶ 路由/状态/请求层 │ 部署上线 ◀── 构建优化 ◀── 代码规范 ◀── 组件开发实践 ◀──────┘ Step 01 · 环境准备 ① 安装 Node.js(版本必须满足 ^20.19.0 || >=22.12.0,这是 Vue 官方文档的硬性要求) 推荐使用 nvm(Windows 用 nvm-windows)管理多版本: nvm install 22 nvm use 22 node -v # 验证 npm -v ② 安装 pnpm(2026 年社区主流选择:磁盘占用小、安装快、幽灵依赖管控严格) npm install -g pnpm pnpm config set registry https://registry.npmmirror.com # 国内镜像加速 ③ 编辑器:VS Code + 插件 Vue - Official(原 Volar,务必禁用旧的 Vetur)。 Step 02 · 创建项目 两条路线,按需选择: 方式命令特点create-vue(官方推荐)pnpm create vue@latest交互式勾选 TS / Router / Pinia / ESLint / Prettier / Vitest,开箱即用create-vite(极简模板)pnpm create vite my-app --template vue-ts只给最干净的骨架,一切自己装,适合想完全掌控配置的人 以官方脚手架为例: pnpm create vue@latest # 交互式选项(建议新手全部按下面选): # ✔ Project name: … my-vue-app # ✔ Add TypeScript? … Yes # ✔ Add JSX Support? … No(需要时再开) # ✔ Add Vue Router? … Yes # ✔ Add Pinia? … Yes # ✔ Add Vitest for Unit Testing? … Yes # ✔ Add ESLint? … Yes(生成 ESLint 9 扁平配置 eslint.config.js) # ✔ Add Prettier? … Yes cd my-vue-app pnpm install pnpm dev # 浏览器打开 http://localhost:5173 💡 实践建议:团队项目优先用 create-vue——它生成的 ESLint 9 flat config、TS 配置、env.d.ts 都是官方校准过的,能避开大量新手坑。 Step 03 · 规划目录结构 脚手架的默认结构只够写 Demo,正式项目建议重构为「按职责分层」: src/ ├── api/ # 接口请求模块(按业务域拆分:user.ts、order.ts) ├── assets/ # 静态资源(图片、字体、全局样式) │ └── styles/ │ ├── variables.scss # 设计变量 │ └── reset.scss # 样式重置 ├── components/ # 全局通用组件(BaseButton、AppHeader…) ├── composables/ # 组合式函数(useXxx,逻辑复用核心) ├── layouts/ # 布局组件(DefaultLayout、BlankLayout) ├── router/ # 路由配置与守卫 │ ├── index.ts │ └── routes.ts ├── stores/ # Pinia 状态模块 │ └── modules/ ├── types/ # 全局 TS 类型声明 ├── utils/ # 工具函数(request.ts、format.ts、storage.ts) ├── views/ # 页面级组件(按路由组织) │ ├── home/ │ └── user/ ├── App.vue └── main.ts 原则一句话:**views**** 只放页面,可复用的进 **components**,可复用的逻辑进 ****composables**。 Step 04 · 核心配置 vite.config.ts import { fileURLToPath, URL } from 'node:url' import { defineConfig, loadEnv } from 'vite' import vue from '@vitejs/plugin-vue' import AutoImport from 'unplugin-auto-import/vite' import Components from 'unplugin-vue-components/vite' export default defineConfig(({ mode }) => { const env = loadEnv(mode, process.cwd()) return { plugins: [ vue(), // 自动导入 ref/computed/watch 等,免去满屏 import AutoImport({ imports: ['vue', 'vue-router', 'pinia'] }), // 组件按需自动注册,无需手动 import + components 声明 Components({ dirs: ['src/components'] }), ], resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)), }, }, css: { preprocessorOptions: { scss: { // 全局注入设计变量,组件内无需重复 @use additionalData: `@use "@/assets/styles/variables.scss" as *;`, }, }, }, server: { port: 5173, open: true, // 开发代理:解决跨域,指向真实后端 proxy: { '/api': { target: env.VITE_API_BASE_URL, changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, ''), }, }, }, build: { target: 'es2020', sourcemap: false, chunkSizeWarningLimit: 1000, rollupOptions: { output: { // 手动分包:第三方库独立 chunk,利用浏览器缓存 manualChunks: { vue: ['vue', 'vue-router', 'pinia'], }, }, }, }, } }) 同步配置 TS 路径别名(tsconfig.app.json): { "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["src/*"] } } } Step 05 · 多环境变量 根目录创建三个文件(注意:只有 **VITE_** 前缀的变量才会暴露给客户端代码): # .env.development VITE_API_BASE_URL=http://localhost:8080 VITE_APP_TITLE=我的应用(开发) # .env.production VITE_API_BASE_URL=https://api.example.com VITE_APP_TITLE=我的应用 补充类型提示(src/types/env.d.ts),让 import.meta.env 有智能补全: ///
interface ImportMetaEnv { readonly VITE_API_BASE_URL: string readonly VITE_APP_TITLE: string } Step 06 · 路由:Vue Router src/router/routes.ts —— 全部使用路由懒加载,首屏只加载当前页面: import type { RouteRecordRaw } from 'vue-router' export const routes: RouteRecordRaw[] = [ { path: '/', component: () => import('@/layouts/DefaultLayout.vue'), children: [ { path: '', name: 'Home', component: () => import('@/views/home/index.vue') }, { path: 'user/:id', name: 'UserDetail', component: () => import('@/views/user/detail.vue'), meta: { title: '用户详情', requiresAuth: true }, }, ], }, { path: '/:pathMatch(.*)*', name: 'NotFound', component: () => import('@/views/404.vue') }, ] src/router/index.ts —— 全局守卫统一处理标题与鉴权: import { createRouter, createWebHistory } from 'vue-router' import { routes } from './routes' import { useUserStore } from '@/stores/modules/user' const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes, scrollBehavior: () => ({ top: 0 }), }) router.beforeEach((to) => { document.title = (to.meta.title as string) ?? import.meta.env.VITE_APP_TITLE const userStore = useUserStore() if (to.meta.requiresAuth && !userStore.isLoggedIn) { return { name: 'Login', query: { redirect: to.fullPath } } } }) export default router Step 07 · 状态管理:Pinia 推荐 Setup Store 写法(与
{{ title }} ② 逻辑复用抽成 Composable(这是 Vue 3 区别于 Vue 2 mixins 的核心红利): src/composables/usePagination.ts import { ref, reactive } from 'vue' export function usePagination(fetcher: (page: number, size: number) => Promise
) { const list = ref([]) const loading = ref(false) const pager = reactive({ page: 1, size: 20, total: 0 }) async function load() { loading.value = true try { list.value = await fetcher(pager.page, pager.size) } finally { loading.value = false } } return { list, loading, pager, load } } ③ 样式策略:组件内用 scoped;主题级变量收敛到 variables.scss 的 CSS 自定义属性,支持暗色模式一行切换。 Step 10 · 代码规范与提交约束 create-vue 已生成 ESLint 9 扁平配置(eslint.config.js),再补两道保险: ① Git Hooks(提交前自动检查 + 格式化): pnpm add -D lint-staged npx husky init // package": ["eslint --fix", "prettier --write"] } } # .husky/pre-commit pnpm lint-staged ② VS Code 保存自动修复(.vscode/settings.json,团队共享): { "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.codeActionsOnSave": { "source.fixAll.eslint": "explicit" }, "eslint.useFlatConfig": true } Step 11 · 构建、验收与部署 pnpm build # 产物输出到 dist/ pnpm preview # 本地起静态服务预览生产包 —— 必做!很多问题只在生产包暴露 部署前验收清单: pnpm build 无 TS 报错、无 chunk 超大警告preview 环境跑通核心链路(登录 → 主要页面 → 刷新不 404)History 模式已配置服务器回退(Nginx 示例如下)静态资源走 CDN,开启 gzip/brotli server { listen 80; root /usr/share/nginx/html; index index.html; location / { try_files $uri $uri/ /index.html; # History 路由回退,关键! } location /api/ { proxy_pass http://backend:8080/; # 生产代理转发 } } Step 12 · 性能优化要点(按需启用) 手段做法路由/组件懒加载() => import(...),配合 defineAsyncComponent第三方库分包manualChunks 拆分 vue 生态 / UI 库 / 图表库图片资源小图转 base64(assetsInlineLimit),大图用 WebP + 懒加载渲染优化v-once、v-memo、长列表虚拟滚动;避免在模板里写复杂表达式依赖预构建Vite 自动处理;大型 CJS 库确认识别正常(看启动日志)体积分析pnpm add -D rollup-plugin-visualizer,构建后看 treemap 找大头 常见坑速查 现象原因 / 解法刷新页面 404History 模式未配 try_files 回退环境变量是 undefined变量名没有 VITE_ 前缀,或改完 .env 没重启 dev server代理不生效 / 仍跨域proxy 的 key 必须和请求的 baseURL 前缀一致@ 别名 TS 报红vite.config.ts 和 tsconfig 要两边都配ESLint 规则不生效ESLint 9 时代认准 eslint.config.js,旧的 .eslintrc 已废弃生产包能跑但白屏多半是 base 路径问题(部署在子目录时需设 base: '/子目录/') 一页纸总结 pnpm create vue@latest ← 官方脚手架,TS + Router + Pinia + ESLint 全勾选 ↓ 重构目录(api / composables / stores / views 分层) ↓ vite.config.ts(别名 @ + 代理 /api + 分包)+ .env 多环境 ↓ 封装 request.ts(拦截器统一 Token 与错误) ↓