Vue3后台管理系统(一):开发环境搭建与项目初始化
一、开发环境准备
- Node.js 16+(推荐最新LTS版本)
- 包管理器:npm 8+(我更推荐使用pnpm)
二、使用Vite创建Vue3项目
bash
# 创建项目
pnpm create vite vue3-admin-template --template vue
# 进入项目目录
cd vue3-admin-template
# 安装依赖
pnpm install
三、项目基础配置
3.1 目录结构规划
|-- vue3-admin-template
|-- src
|-- api # API接口管理
|-- assets # 静态资源
|-- components # 公共组件
|-- composables # 组合式功能(hooks)
|-- directives # 自定义指令
|-- layout # 布局组件
|-- router # 路由配置
|-- stores # Pinia状态管理
|-- styles # 全局样式
|-- utils # 工具函数
|-- views # 页面组件
|-- App.vue # 根组件
|-- main.js # 入口文件
|-- .env.development # 开发环境变量
|-- .env.production # 生产环境变量
|-- .env.test # 测试环境变量
|-- vite.config.js # Vite配置
|-- package.json # 项目配置
|-- index.html # HTML模板
3.2 Vite配置
javascript
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue' // Vue3插件,使Vite支持.vue文件
import path from 'path' // Node.js内置模块,用于处理文件路径
import AutoImport from 'unplugin-auto-import/vite' // 自动导入API插件
import Components from 'unplugin-vue-components/vite' // 自动导入组件插件
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers' // Element Plus组件解析器
import viteCompression from 'vite-plugin-compression' // 构建压缩插件
import vueDevTools from 'vite-plugin-vue-devtools' // Vue DevTools增强插件
export default defineConfig({
base: '/', // 部署应用的基础URL,通常设置为'/'表示根路径
plugins: [
vue(), // 启用Vue3插件
vueDevTools(), // 增强Vue开发工具,提供更好的调试体验
AutoImport({
resolvers: [ElementPlusResolver()], // 使用Element Plus解析器
imports: ['vue', 'vue-router', 'pinia'] // 自动导入Vue、Vue Router、Pinia API,无需手动import
// 技巧:自动导入可以减少大量重复的import语句,使代码更简洁
}),
Components({
resolvers: [ElementPlusResolver()] // 自动导入Element Plus组件,无需手动注册
// 技巧:按需导入组件可以减少最终打包体积
}),
viteCompression({
verbose: true, // 是否在控制台输出压缩结果
disable: false, // 是否禁用压缩
threshold: 10240, // 文件大小超过10KB才会被压缩
algorithm: 'gzip', // 使用gzip算法
ext: '.gz', // 生成的压缩包扩展名
// 技巧:启用gzip压缩可以显著减少传输文件大小,提升加载速度
})
],
resolve: {
alias: {
'@': path.resolve(__dirname, 'src') // 路径别名,使用@代替src路径
// 技巧:路径别名可以简化导入路径,避免使用繁琐的相对路径
},
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'], // 导入时可以省略的扩展名
},
css: {
preprocessorOptions: {
scss: {
additionalData: `@use "@/styles/variables.scss" as *;`, // 全局注入SCSS变量
// 技巧:这样可以在所有组件中直接使用变量,无需每个文件都import
},
},
},
server: {
port: 3000, // 开发服务器端口
open: true, // 启动时自动打开浏览器
},
build: {
target: 'es2015', // 构建目标环境
minify: 'terser', // 使用terser进行代码压缩
terserOptions: {
compress: {
drop_debugger: true, // 移除debugger语句
pure_funcs: ['console.log', 'console.debug', 'console.trace'], // 移除console语句
// 技巧:生产环境中移除console语句可以减小打包体积并避免信息泄露
},
output: {
comments: false, // 移除注释
},
},
brotliSize: true, // 启用brotli压缩大小报告
chunkSizeWarningLimit: 2000, // 警告体积超过2000KB的chunks
assetsInlineLimit: 4096, // 小于4KB的资源将被内联为base64
sourcemap: false, // 不生成sourcemap,减小构建体积
assetsDir: `assets.${new Date().getTime()}`, // 资源目录添加时间戳避免缓存问题
// 技巧:时间戳可以防止浏览器缓存旧资源
rollupOptions: {
output: {
manualChunks: {
'vendor': ['vue', 'vue-router', 'pinia'], // 将核心库打包到vendor chunk
'alova': ['alova', 'alova/client'], // HTTP请求库单独打包
'element-plus': ['element-plus'], // UI组件库单独打包
'icons': ['@element-plus/icons-vue'], // 图标单独打包
'utils': [
'crypto-js',
'nprogress',
'autofit.js',
], // 工具库单独打包
// 技巧:手动分chunk可以更好地利用缓存,避免一处修改导致所有文件失效
},
chunkFileNames: `js/[name].[hash].${new Date().getTime()}.js`, // chunk文件名格式
entryFileNames: `js/[name].[hash].${new Date().getTime()}.js`, // 入口文件名格式
// 技巧:添加时间戳可以确保每次构建生成不同的文件名,避免CDN或浏览器缓存问题
}
}
}
})
这个配置包含了以下核心功能:
- 路径别名(@指向src目录)
- Element Plus组件和API的按需自动导入
- 构建时的Gzip压缩
- 开发服务器配置(端口、自动打开浏览器)
- 构建优化(去除控制台日志、代码分割)
- Vue DevTools增强插件
- CSS预处理器配置
3.3 环境变量配置
# .env.development
NODE_ENV=development
VITE_APP_TITLE=Vue3后台管理系统(开发环境)
VITE_APP_API_BASE_URL=/api
VITE_APP_UPLOAD_URL=/api/upload
# .env.production
NODE_ENV=production
VITE_APP_TITLE=Vue3后台管理系统
VITE_APP_API_BASE_URL=https://api.example.com
VITE_APP_UPLOAD_URL=https://api.example.com/upload
# .env.test
NODE_ENV=test
VITE_APP_TITLE=Vue3后台管理系统(测试环境)
VITE_APP_API_BASE_URL=https://test-api.example.com
VITE_APP_UPLOAD_URL=https://test-api.example.com/upload
# API 配置(开发环境使用测试API)
VITE_API_BASE_URL=https://filling-service.xjy2.cn
# 文件上传配置(开发环境使用测试服务)
VITE_OSS_BASE_URL=//oss-test.xjy0.cn/api/upload
# 环境配置
VITE_APP_ENV=development
在代码中,可以通过i
访问这些环境变量:
javascript
console.log(import.meta.env.VITE_APP_API_BASE_URL)
四、核心依赖安装
4.1 安装Vue全家桶
bash
# Vue核心库、路由、状态管理
pnpm add vue vue-router@4 pinia
4.2 UI组件库
本项目使用Element Plus作为UI组件库:
bash
# 安装Element Plus及图标库
pnpm add element-plus @element-plus/icons-vue
4.3 工具库
我们还需要一些常用的工具库:
bash
# HTTP请求库 - 这里使用alova替代axios
pnpm add alova
# 加密工具
pnpm add crypto-js encryptlong
# Excel数据处理
pnpm add exceljs file-saver
# 进度条
pnpm add nprogress
# 自适应布局
pnpm add autofit.js
五、项目的初始化结构
5.1 入口文件
javascript
// src/main.js
import { createApp } from 'vue' // 创建Vue应用的核心API
import { createPinia } from 'pinia' // 创建Pinia状态管理实例
import ElementPlus from 'element-plus' // Element Plus组件库
import * as ElementPlusIconsVue from '@element-plus/icons-vue' // 引入所有Element Plus图标
import autofit from 'autofit.js' // 自适应布局工具
import 'element-plus/dist/index.css' // Element Plus样式
import './styles/index.scss' // 全局样式
import App from './App.vue' // 根组件
import router from './router' // 路由
import zhCn from 'element-plus/dist/locale/zh-cn.mjs' // Element Plus中文语言包
import { setupPermissionDirective } from './directives/permission' // 权限指令
// 应用实例
const app = createApp(App)
// Pinia 实例
const pinia = createPinia()
app.use(pinia)
// 按需引入核心图标
const coreIcons = ['Plus', 'Search', 'Upload', 'ArrowDown', 'Close']
// 优先注册核心图标
for (const key of coreIcons) {
if (ElementPlusIconsVue[key]) {
app.component(key, ElementPlusIconsVue[key])
}
}
// 在页面空闲时注册其他图标
if (window.requestIdleCallback) {
requestIdleCallback(() => {
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
if (!coreIcons.includes(key)) {
app.component(key, component)
}
}
})
} else {
// 兼容不支持requestIdleCallback的浏览器
setTimeout(() => {
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
if (!coreIcons.includes(key)) {
app.component(key, component)
}
}
}, 300)
}
// 技巧:图标分批注册性能优化
// 1. 先注册核心常用图标,确保首屏渲染所需图标立即可用
// 2. 其他图标在浏览器空闲时再注册,避免阻塞主线程
// 3. 使用requestIdleCallback API可以在浏览器空闲时执行低优先级任务
// 4. 提供降级方案确保兼容性,setTimeout作为备选方案
// 注册权限指令
setupPermissionDirective(app)
// 安装其他插件
app.use(ElementPlus, {
locale: zhCn, // 设置Element Plus为中文
})
app.use(router)
// 初始化 autofit
autofit.init({
el: '#app', // 目标元素
dw: 1920, // 设计图宽度
dh: 1040, // 设计图高度,根据设计图按照实际情况调整
resize: true, // 是否在窗口大小变化时重新计算
transition: 0.3, // 过渡动画时间(秒)
limit: 0.1, // 最小缩放比例限制
cssMode: 'scale', // 使用scale方式缩放,保持比例
allowScroll: false, // 禁止滚动,保持整体布局
// 技巧:使用autofit.js实现全局自适应缩放
// 1. 适合大屏项目和管理系统,可以保持一致的展示效果
// 2. 不同于自适应布局,整体缩放可以保持元素间的相对位置不变
// 3. 结合limit参数可以避免过度缩小导致内容不可读
})
// 页面挂载
app.mount('#app')
javascript
// .prettierrc
{
"semi": false, // 不使用分号结尾
"singleQuote": true, // 使用单引号代替双引号
"useTabs": true, // 使用Tab而非空格进行缩进
"tabWidth": 2, // Tab等效的空格数为2
"trailingComma": "es5", // ES5中有效的尾随逗号(数组、对象等)
"printWidth": 100, // 行宽为100字符,超出换行
"bracketSpacing": true, // 对象字面量中的括号前后添加空格
"arrowParens": "always", // 箭头函数参数始终使用括号,即使只有一个参数
"endOfLine": "auto", // 自动识别换行符
"htmlWhitespaceSensitivity": "css", // HTML空白符敏感度按CSS display属性决定
"insertPragma": false, // 不在文件顶部插入@prettier特殊注释
"bracketSameLine": false, // HTML标签的闭合括号不与最后一个属性在同一行
"quoteProps": "as-needed", // 对象属性只在必要时使用引号
"vueIndentScriptAndStyle": false // 不缩进Vue文件中的script和style标签内容
}
"scripts": {
"format": "prettier --write \"src/**/*.{js,jsx,vue,scss,css,json,md}\""
}