Files

215 lines
7.0 KiB
TypeScript

import { ConfigEnv, UserConfig, defineConfig, loadEnv } from 'vite'
import viteCompression from 'vite-plugin-compression'
import vue from '@vitejs/plugin-vue'
import path from 'path'
import { visualizer } from 'rollup-plugin-visualizer' // 打包分析插件
import { constants } from 'zlib' // 静态引入zlib常量
import Components from 'unplugin-vue-components/vite'
import AutoImport from 'unplugin-auto-import/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
// 获取当前时间戳,用于构建输出的文件名
const Timestamp = new Date().getTime();
// 路径解析辅助函数
function _resolve(dir: string) {
return path.resolve(__dirname, dir);
}
export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
// 判断当前是否为生产环境
const isProd = mode === 'production'
// 加载环境变量文件(.env)
const env = loadEnv(mode, process.cwd())
const enableVisualizer = isProd && env.VITE_VISUALIZER === 'true'
return {
// 基础公共路径,从环境变量VITE_ADDRESS_BASE_URL获取
base: env.VITE_ADDRESS_BASE_URL,
// CSS预处理器配置
css: {
preprocessorOptions: {
scss: {
api: 'modern-compiler', // 使用现代Sass编译器API
silenceDeprecations: ['legacy-js-api'],
additionalData: `@use "@/assets/styles/variables" as *; @use "@/assets/styles/mixins" as *;`
}
}
},
// 插件配置
plugins: [
// Vue插件
vue(),
// Gzip压缩插件(仅生产环境启用)
viteCompression({
verbose: true, // 显示压缩日志
disable: !isProd, // 非生产环境禁用
deleteOriginFile: false, // 不删除源文件
threshold: 1024, // 文件大小1KB才压缩(降低阈值)
algorithm: 'gzip', // 压缩算法
ext: '.gz', // 压缩文件扩展名
compressionOptions: {
level: 9, // 最高压缩级别
}
}),
// 添加Brotli压缩支持(更高效的压缩算法)
isProd && viteCompression({
verbose: true,
disable: !isProd,
deleteOriginFile: false,
threshold: 1024,
algorithm: 'brotliCompress',
ext: '.br',
compressionOptions: {
params: {
[constants.BROTLI_PARAM_QUALITY]: 11, // 最高质量
}
}
}),
// Auto-import Element Plus components from templates
Components({
resolvers: [ElementPlusResolver({ importStyle: 'css' })],
dts: false
}),
// Auto-import Element Plus APIs (ElMessage, ElNotification, etc.)
AutoImport({
resolvers: [ElementPlusResolver()],
imports: ['vue', 'vue-router', 'pinia'],
dts: false
}),
// 打包分析插件(仅在显式启用时生效;容器/CI 默认不打开浏览器)
enableVisualizer && visualizer({ open: false })
].filter(Boolean), // 过滤掉false的插件
// 开发服务器配置
server: {
host: '0.0.0.0', // 监听所有IP
port: 3000, // 端口号
open: true, // 自动打开浏览器
// https: false, // 不启用HTTPS
cors: true, // 启用CORS
// 开发环境热更新优化
hmr: {
overlay: true
},
// WSL2热更新修复
watch: {
usePolling: true,
interval: 1000
},
},
// 依赖优化配置
optimizeDeps: {
include: [
'vue',
'vue-router',
'pinia',
'element-plus',
'@element-plus/icons-vue',
'axios',
'vue-i18n',
'echarts/core',
'echarts/charts',
'echarts/components',
'echarts/renderers',
'vue-echarts',
'@vueuse/core'
]
},
// 模块解析配置
resolve: {
alias: { // 路径别名
'@': _resolve('src'), // 源码目录
'@assets': _resolve('src/assets'), // 资源目录
'@views': _resolve('src/views'), // 视图目录
'@components': _resolve('src/components'), // 组件目录
'@utils': _resolve('src/utils'), // 工具函数
'@router': _resolve('src/router'), // 路由配置
'@store': _resolve('src/store'), // 状态管理
}
},
// ESBuild配置
esbuild: {
pure: isProd ? ["console.log", "debugger"] : [] // 生产环境移除console.log和debugger
},
// 构建配置
build: {
minify: 'terser', // 使用terser进行代码压缩
assetsInlineLimit: 4 * 1024, // 小于4KB的资源转为base64(优化)
sourcemap: !isProd, // 开发环境生成sourcemap,生产环境不生成
outDir: env.VITE_OUTDIR || 'dist', // 输出目录
emptyOutDir: true, // 构建前清空输出目录
chunkSizeWarningLimit: 1000, // 降低块大小警告阈值至1MB
cssCodeSplit: true, // CSS代码分割
terserOptions: {
compress: {
drop_console: isProd, // 生产环境移除console
drop_debugger: isProd, // 生产环境移除debugger
pure_funcs: isProd ? ['console.log'] : [], // 移除纯函数调用
// 额外的压缩优化
dead_code: true, // 移除无用代码
keep_infinity: true, // 保持Infinity
toplevel: isProd, // 顶级作用域压缩
},
mangle: {
toplevel: isProd, // 顶级作用域变量名压缩
}
},
rollupOptions: { // Rollup打包配置
// 启用构建缓存以提升重复构建速度
cache: isProd, // 生产环境启用Rollup缓存
output: {
// 优化的手动分块策略
manualChunks: {
// Vue core
vue: ['vue', 'vue-router', 'pinia'],
// Element Plus (tree-shaken via auto-import, but base bundle still needed)
elementPlus: ['element-plus'],
// Element Plus icons
elementIcons: ['@element-plus/icons-vue'],
// ECharts (large library, isolated for better caching)
echarts: ['echarts', 'vue-echarts'],
// Utilities
utils: ['axios'],
// i18n
vendor: ['vue-i18n']
},
// 输出文件命名规则(优化缓存策略)
chunkFileNames: `static/js/[name].[hash].js`,
entryFileNames: `static/js/[name].[hash].js`,
assetFileNames: (assetInfo) => {
const name = assetInfo.name || ''
if (/\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/i.test(name)) {
return `static/media/[name].[hash][extname]`
} else if (/\.(png|jpe?g|gif|svg|ico|webp)(\?.*)?$/i.test(name)) {
return `static/images/[name].[hash][extname]`
} else if (/\.(woff2?|eot|ttf|otf)(\?.*)?$/i.test(name)) {
return `static/fonts/[name].[hash][extname]`
} else {
return `static/assets/[name].[hash][extname]`
}
}
},
// 外部化依赖(CDN优化,可选)
external: isProd ? [] : []
}
},
// JSON文件处理配置
json: {
stringify: false
}
}
})