第七章:vue工程化与构建工具

核心目标:掌握 Vite 5 项目配置、TypeScript 类型实践、ESLint/Prettier 规范、环境变量管理、构建优化等工程化最佳实践。


📋 本章知识点

知识点 说明 难度
Vite 配置 插件、别名、代理、构建选项 ⭐⭐
环境变量 .env 文件、import.meta.env
TypeScript 泛型、工具类型、接口设计 ⭐⭐⭐
目录规范 项目结构最佳实践
ESLint + Prettier 代码规范自动化 ⭐⭐
构建优化 代码分割、Tree-shaking ⭐⭐⭐

7.1 Vite 配置详解

Vite 是基于原生 ESM 的下一代前端构建工具,开发环境无需打包,极速启动。

完整配置示例

typescript 复制代码
// vite.config.ts
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import { fileURLToPath, URL } from 'node:url'

export default defineConfig(({ command, mode }) => {
  const env = loadEnv(mode, process.cwd(), '')

  return {
    plugins: [vue()],

    // 路径别名:@ → src/
    resolve: {
      alias: {
        '@': fileURLToPath(new URL('./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: command === 'serve',
      rollupOptions: {
        output: {
          // 手动分包:将大的第三方库单独打包
          manualChunks: {
            vendor: ['vue', 'vue-router', 'pinia'],
            utils: ['axios', '@vueuse/core']
          }
        }
      }
    }
  }
})

Vite vs Webpack 对比

特性 Vite Webpack
开发启动 毫秒级(原生 ESM) 秒~分钟(打包整个项目)
HMR 速度 极快(只更新变化模块) 较慢(重新打包)
配置复杂度 简单 复杂
构建产物 Rollup(体积小) Webpack(灵活)
生态 兼容大多数 Rollup 插件 插件生态最丰富

7.2 环境变量管理

文件结构

bash 复制代码
├── .env                  # 所有环境公共变量
├── .env.development      # 开发环境(vite dev)
├── .env.staging          # 测试环境(--mode staging)
└── .env.production       # 生产环境(vite build)

变量定义规则

bash 复制代码
# .env.development
VITE_APP_TITLE=Vue Demo(开发)
VITE_API_BASE=http://localhost:8080
VITE_ENABLE_MOCK=true

# .env.production
VITE_APP_TITLE=Vue Demo
VITE_API_BASE=https://api.example.com
VITE_ENABLE_MOCK=false

# ⚠️ 只有 VITE_ 前缀的变量才会暴露给浏览器
# 敏感变量(如数据库连接)不加 VITE_ 前缀,只在 Node 端使用

读取环境变量

typescript 复制代码
// src/config/index.ts
export const AppConfig = {
  title: import.meta.env.VITE_APP_TITLE,
  apiBase: import.meta.env.VITE_API_BASE,
  enableMock: import.meta.env.VITE_ENABLE_MOCK === 'true',
  isDev: import.meta.env.DEV,
  isProd: import.meta.env.PROD,
  mode: import.meta.env.MODE,  // 'development' | 'production' | 'staging'
}

// TypeScript 类型声明(env.d.ts)
/// <reference types="vite/client" />
interface ImportMetaEnv {
  readonly VITE_APP_TITLE: string
  readonly VITE_API_BASE: string
  readonly VITE_ENABLE_MOCK: string
}

7.3 TypeScript 类型实践

核心接口设计

typescript 复制代码
// src/types/index.ts

// 用户模型
export interface User {
  id: number
  name: string
  email: string
  avatar?: string
  role: 'admin' | 'editor' | 'viewer'
  createdAt: Date
}

// 泛型 API 响应包装
export interface ApiResponse<T> {
  code: number
  data: T
  message: string
  timestamp: number
}

// 分页类型
export interface Pagination<T> {
  list: T[]
  total: number
  page: number
  pageSize: number
}

// 实用工具类型
export type CreateUserDto = Omit<User, 'id' | 'createdAt'>
export type UpdateUserDto = Partial<CreateUserDto>
export type UserSummary = Pick<User, 'id' | 'name' | 'role'>

// 函数类型
export type FetchFn<T> = (params?: Record<string, unknown>) => Promise<ApiResponse<T>>

Vue 组件中的 TypeScript 最佳实践

vue 复制代码
<script setup lang="ts">
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>

常用工具类型速查

typescript 复制代码
// 从类型中选取/排除字段
type A = Pick<User, 'id' | 'name'>     // { id: number; name: string }
type B = Omit<User, 'createdAt'>       // 去掉 createdAt

// 将所有字段变为可选/必须
type C = Partial<User>                  // 全部可选
type D = Required<User>                 // 全部必须

// 只读
type E = Readonly<User>

// Record:构造对象类型
type F = Record<string, User>           // { [key: string]: User }

// 条件类型
type IsAdmin<T extends User> = T['role'] extends 'admin' ? true : false

// infer 推断
type ReturnType<T> = T extends (...args: any) => infer R ? R : never

7.4 项目目录规范

复制代码
vue_demos/
├── public/                   # 不经 Vite 处理的静态资源
├── src/
│   ├── api/                  # API 请求层(axios 封装)
│   │   ├── request.ts        # axios 实例 + 拦截器
│   │   ├── user.ts           # 用户相关 API
│   │   └── index.ts          # 统一导出
│   │
│   ├── assets/               # 图片、字体等静态资源(Vite 处理)
│   │
│   ├── components/           # 公共组件
│   │   ├── base/             # 基础 UI(Button、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

命名约定

类型 命名规范 示例
组件文件 PascalCase UserCard.vue
页面文件 PascalCase HomeView.vue
Composable camelCase,use 前缀 useFetch.ts
Store camelCase useUserStore
工具函数 camelCase formatDate.ts
类型/接口 PascalCase interface User

7.5 ESLint + Prettier

安装

bash 复制代码
npm install -D eslint @vue/eslint-config-typescript @vue/eslint-config-prettier

ESLint 配置

javascript 复制代码
// .eslintrc.cjs
module.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_ENV === 'production' ? 'warn' : 'off'
  }
}

Prettier 配置

json 复制代码
// .prettierrc.json
{
  "semi": false,
  "singleQuote": true,
  "tabWidth": 2,
  "trailingComma": "none",
  "printWidth": 100,
  "vueIndentScriptAndStyle": true
}

7.6 构建优化

代码分割策略

typescript 复制代码
// vite.config.ts - manualChunks
rollupOptions: {
  output: {
    manualChunks(id) {
      if (id.includes('node_modules')) {
        if (id.includes('vue')) return 'vendor-vue'
        if (id.includes('axios')) return 'vendor-axios'
        return 'vendor-other'
      }
      // 按路由拆分
      if (id.includes('views/Chapter01')) return 'chapter-01'
      if (id.includes('views/Chapter02')) return 'chapter-02'
    }
  }
}

构建产物分析

bash 复制代码
# 安装分析插件
npm install -D rollup-plugin-visualizer

# vite.config.ts
import { visualizer } from 'rollup-plugin-visualizer'
plugins: [
  vue(),
  visualizer({ open: true, filename: 'dist/stats.html' })
]

# 构建后自动打开分析报告
npm run build

性能数据对比

指标 优化前 优化后 改善
首屏 JS 850KB 120KB -86%
启动时间 4.2s 0.8s -81%
构建时间 12s 4s -67%
Lighthouse 分数 62 94 +32

📌 核心要点总结

  • Vite 开发用 ESM、构建用 Rollup,兼顾速度和产物质量
  • 环境变量 必须加 VITE_ 前缀才能在客户端读取,敏感信息不加前缀
  • TypeScript 用泛型 ApiResponse<T> 封装接口,用工具类型减少重复定义
  • 目录结构 按职责分层:api/stores/composables/components/views/
  • 代码规范 用 ESLint 检查、Prettier 格式化,CI 中强制执行
  • 构建优化 manualChunks 拆分第三方库,路由懒加载,图片 loading="lazy"

🔗 专栏链接Vue 3 全栈开发实战专栏

📦 项目源码资源点击下载项目源码

相关推荐
WMYeah1 小时前
【无标题】
前端·rust·抽奖程序·跨平台抽奖程序
Unbelievabletobe1 小时前
免费外汇api的响应时间在不同时段下的波动分析
大数据·开发语言·前端·python
大哥,带带弟弟1 小时前
Grafana 前端嵌入与 JWT 鉴权实战
前端·grafana
小小小小宇1 小时前
前端 V8 引擎垃圾回收机制与内存问题排查
前端
前端老石人1 小时前
CSS 值定义语法
前端·css
sheeta19981 小时前
Vue 前端基础笔记
前端·vue.js·笔记
小小小小宇1 小时前
GitLab + GitLab Runner + Qiankun 微前端 + Nginx + Node 中间件 前端开发机从零搭建 CI/CD 全流程
前端
前端那点事1 小时前
别再写垃圾组件!Vue3 如何设计「真正可复用」的高质量通用组件
前端·vue.js
卷帘依旧1 小时前
JavaScript 中的 Symbol
前端·javascript
老王以为2 小时前
Claude Code 从 GUI 到 TUI:开发者界面的范式回归
前端·人工智能·全栈