215 lines
7.0 KiB
TypeScript
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
|
|
}
|
|
}
|
|
}) |