第七章: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 全栈开发实战专栏

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

相关推荐
zhensherlock2 小时前
Protocol Launcher 系列:Trello 看板管理的协议自动化
前端·javascript·typescript·node.js·自动化·github·js
zhuà!2 小时前
element的el-form提交校验没反应问题
前端·elementui
龙猫里的小梅啊2 小时前
CSS(一)CSS基础语法与样式引入
前端·css
小码哥_常2 小时前
从0到1,开启Android音视频开发之旅
前端
渔舟小调2 小时前
P19 | 前端加密通信层 pikachuNetwork.js 完整实现
开发语言·前端·javascript
qq_12084093713 小时前
Three.js 工程向:Draw Call 预算治理与渲染批处理实践
前端·javascript
旷世奇才李先生4 小时前
Vue3\+Vite\+Pinia实战:企业级后台管理系统完整实现(附源码)
vue.js
不会聊天真君6475 小时前
JavaScript基础语法(Web前端开发笔记第三期)
前端·javascript·笔记