第七章:vue工程化与构建工具
核心目标掌握 Vite 5 项目配置、TypeScript 类型实践、ESLint/Prettier 规范、环境变量管理、构建优化等工程化最佳实践。 本章知识点知识点说明难度Vite 配置插件、别名、代理、构建选项⭐⭐环境变量.env文件、import.meta.env⭐TypeScript泛型、工具类型、接口设计⭐⭐⭐目录规范项目结构最佳实践⭐ESLint Prettier代码规范自动化⭐⭐构建优化代码分割、Tree-shaking⭐⭐⭐7.1 Vite 配置详解Vite 是基于原生 ESM 的下一代前端构建工具开发环境无需打包极速启动。完整配置示例// vite.config.tsimport{defineConfig,loadEnv}fromviteimportvuefromvitejs/plugin-vueimport{fileURLToPath,URL}fromnode:urlexportdefaultdefineConfig(({command,mode}){constenvloadEnv(mode,process.cwd(),)return{plugins:[vue()],// 路径别名 → src/resolve:{alias:{:fileURLToPath(newURL(./src,import.meta.url))}},// 开发服务器server:{port:3000,open:true,proxy:{/api:{target:env.VITE_API_BASE||http://localhost:8080,changeOrigin:true,rewrite:(path)path.replace(/^\/api/,)}}},// 构建优化build:{target:es2015,sourcemap:commandserve,rollupOptions:{output:{// 手动分包将大的第三方库单独打包manualChunks:{vendor:[vue,vue-router,pinia],utils:[axios,vueuse/core]}}}}}})Vite vs Webpack 对比特性ViteWebpack开发启动毫秒级原生 ESM秒~分钟打包整个项目HMR 速度极快只更新变化模块较慢重新打包配置复杂度简单复杂构建产物Rollup体积小Webpack灵活生态兼容大多数 Rollup 插件插件生态最丰富7.2 环境变量管理文件结构├── .env# 所有环境公共变量├── .env.development# 开发环境vite dev├── .env.staging# 测试环境--mode staging└── .env.production# 生产环境vite build变量定义规则# .env.developmentVITE_APP_TITLEVue Demo开发VITE_API_BASEhttp://localhost:8080VITE_ENABLE_MOCKtrue# .env.productionVITE_APP_TITLEVue DemoVITE_API_BASEhttps://api.example.comVITE_ENABLE_MOCKfalse# ⚠️ 只有 VITE_ 前缀的变量才会暴露给浏览器# 敏感变量如数据库连接不加 VITE_ 前缀只在 Node 端使用读取环境变量// src/config/index.tsexportconstAppConfig{title:import.meta.env.VITE_APP_TITLE,apiBase:import.meta.env.VITE_API_BASE,enableMock:import.meta.env.VITE_ENABLE_MOCKtrue,isDev:import.meta.env.DEV,isProd:import.meta.env.PROD,mode:import.meta.env.MODE,// development | production | staging}// TypeScript 类型声明env.d.ts/// reference typesvite/client /interfaceImportMetaEnv{readonlyVITE_APP_TITLE:stringreadonlyVITE_API_BASE:stringreadonlyVITE_ENABLE_MOCK:string}7.3 TypeScript 类型实践核心接口设计// src/types/index.ts// 用户模型exportinterfaceUser{id:numbername:stringemail:stringavatar?:stringrole:admin|editor|viewercreatedAt:Date}// 泛型 API 响应包装exportinterfaceApiResponseT{code:numberdata:Tmessage:stringtimestamp:number}// 分页类型exportinterfacePaginationT{list:T[]total:numberpage:numberpageSize:number}// 实用工具类型exporttypeCreateUserDtoOmitUser,id|createdAtexporttypeUpdateUserDtoPartialCreateUserDtoexporttypeUserSummaryPickUser,id|name|role// 函数类型exporttypeFetchFnT(params?:Recordstring,unknown)PromiseApiResponseTVue 组件中的 TypeScript 最佳实践script setup langts import { ref, computed } from vue import type { User, UpdateUserDto } from /types // defineProps 类型 const props defineProps{ user: User readonly?: boolean }() // withDefaults 设置默认值 const propsWithDefaults withDefaults(defineProps{ size?: sm | md | lg disabled?: boolean }(), { size: md, disabled: false }) // defineEmits 类型 const emit defineEmits{ update: [value: UpdateUserDto] delete: [id: number] cancel: [] }() // defineExpose 暴露方法给父组件 defineExpose({ focus: () inputRef.value?.focus() }) /script常用工具类型速查// 从类型中选取/排除字段typeAPickUser,id|name// { id: number; name: string }typeBOmitUser,createdAt// 去掉 createdAt// 将所有字段变为可选/必须typeCPartialUser// 全部可选typeDRequiredUser// 全部必须// 只读typeEReadonlyUser// Record构造对象类型typeFRecordstring,User// { [key: string]: User }// 条件类型typeIsAdminTextendsUserT[role]extendsadmin?true:false// infer 推断typeReturnTypeTTextends(...args:any)inferR?R:never7.4 项目目录规范vue_demos/ ├── public/ # 不经 Vite 处理的静态资源 ├── src/ │ ├── api/ # API 请求层axios 封装 │ │ ├── request.ts # axios 实例 拦截器 │ │ ├── user.ts # 用户相关 API │ │ └── index.ts # 统一导出 │ │ │ ├── assets/ # 图片、字体等静态资源Vite 处理 │ │ │ ├── components/ # 公共组件 │ │ ├── base/ # 基础 UIButton、Input、Modal... │ │ └── business/ # 业务组件UserCard、OrderList... │ │ │ ├── composables/ # 可复用逻辑useXxx 命名 │ │ ├── useFetch.ts │ │ ├── useDebounce.ts │ │ └── useLocalStorage.ts │ │ │ ├── router/ # Vue Router │ │ └── index.ts │ │ │ ├── stores/ # Pinia 状态管理 │ │ ├── user.ts │ │ └── index.ts │ │ │ ├── types/ # TypeScript 类型定义只放类型 │ │ └── index.ts │ │ │ ├── utils/ # 纯工具函数无副作用 │ │ ├── format.ts # 日期、数字格式化 │ │ └── validate.ts # 表单验证 │ │ │ ├── views/ # 页面组件路由级 │ │ └── Chapter01_Basics/ │ │ └── BasicsDemo.vue │ │ │ ├── App.vue │ ├── main.ts │ └── style.css # 全局样式 CSS 变量 │ ├── .env ├── .env.development ├── .env.production ├── index.html ├── package.json ├── tsconfig.json └── vite.config.ts命名约定类型命名规范示例组件文件PascalCaseUserCard.vue页面文件PascalCaseHomeView.vueComposablecamelCaseuse 前缀useFetch.tsStorecamelCaseuseUserStore工具函数camelCaseformatDate.ts类型/接口PascalCaseinterface User7.5 ESLint Prettier安装npminstall-Deslint vue/eslint-config-typescript vue/eslint-config-prettierESLint 配置// .eslintrc.cjsmodule.exports{root:true,extends:[plugin:vue/vue3-essential,eslint:recommended,vue/eslint-config-typescript,vue/eslint-config-prettier/skip-formatting],parserOptions:{ecmaVersion:latest},rules:{vue/multi-word-component-names:off,vue/define-macros-order:[error,{order:[defineOptions,defineProps,defineEmits,defineExpose]}],typescript-eslint/no-explicit-any:warn,no-console:process.env.NODE_ENVproduction?warn:off}}Prettier 配置// .prettierrc.json{semi:false,singleQuote:true,tabWidth:2,trailingComma:none,printWidth:100,vueIndentScriptAndStyle:true}7.6 构建优化代码分割策略// vite.config.ts - manualChunksrollupOptions:{output:{manualChunks(id){if(id.includes(node_modules)){if(id.includes(vue))returnvendor-vueif(id.includes(axios))returnvendor-axiosreturnvendor-other}// 按路由拆分if(id.includes(views/Chapter01))returnchapter-01if(id.includes(views/Chapter02))returnchapter-02}}}构建产物分析# 安装分析插件npminstall-Drollup-plugin-visualizer# vite.config.tsimport{visualizer}fromrollup-plugin-visualizerplugins:[vue(), visualizer({open: true, filename:dist/stats.html})]# 构建后自动打开分析报告npmrun build性能数据对比指标优化前优化后改善首屏 JS850KB120KB-86%启动时间4.2s0.8s-81%构建时间12s4s-67%Lighthouse 分数629432 核心要点总结Vite开发用 ESM、构建用 Rollup兼顾速度和产物质量环境变量必须加VITE_前缀才能在客户端读取敏感信息不加前缀TypeScript用泛型ApiResponseT封装接口用工具类型减少重复定义目录结构按职责分层api/→stores/→composables/→components/→views/代码规范用 ESLint 检查、Prettier 格式化CI 中强制执行构建优化manualChunks拆分第三方库路由懒加载图片loadinglazy专栏链接Vue 3 全栈开发实战专栏项目源码资源点击下载项目源码