import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; import ViteCompression from 'vite-plugin-compression'; import ViteComponents from 'unplugin-vue-components/vite'; import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers'; import { EleAdminResolver } from 'ele-admin-pro/lib/utils/resolvers'; import { DynamicAntdLess } from 'ele-admin-pro/lib/utils/dynamic-theme'; import { resolve } from 'path'; import { visualizer } from 'rollup-plugin-visualizer'; import { splitVendorChunkPlugin } from 'vite'; export default defineConfig(({ command }) => { const isBuild = command === 'build'; return { // 在这里增加 base 写子路径 base: '/', resolve: { alias: { '@/': resolve('src') + '/', 'vue-i18n': 'vue-i18n/dist/vue-i18n.cjs.js' } }, // server: { // proxy: { // '/api': 'https://server.websoft.top' // } // }, plugins: [ vue({ script: { defineModel: true, propsDestructure: true } }), // 组件按需引入 ViteComponents({ dts: false, resolvers: [ AntDesignVueResolver({ importStyle: isBuild ? 'less' : false }), EleAdminResolver({ importStyle: isBuild ? 'less' : false }) ], directoryAsNamespace: true }), // 代码分割 splitVendorChunkPlugin(), // gzip 压缩 ViteCompression({ disable: !isBuild, threshold: 10240, algorithm: 'gzip', ext: '.gz' }), // brotli 压缩 ViteCompression({ disable: !isBuild, threshold: 10240, algorithm: 'brotliCompress', ext: '.br' }), // 打包分析 isBuild && visualizer({ filename: 'dist/stats.html', open: false, gzipSize: true, brotliSize: true }) ].filter(Boolean), css: { preprocessorOptions: { less: { javascriptEnabled: true, plugins: [new DynamicAntdLess()], modifyVars: { // 组件样式开发环境全局引入生产环境按需引入 'style-entry-file': isBuild ? 'as-needed' : 'global-import' } } } }, optimizeDeps: { include: [ 'sortablejs', 'vuedraggable', 'echarts/core', 'echarts/charts', 'echarts/renderers', 'echarts/components', 'vue-echarts', 'echarts-wordcloud', 'xlsx', 'lodash-es', 'dayjs', 'crypto-js', 'js-md5', 'qrcode', 'nprogress' ], exclude: ['@iconify/json'] }, build: { target: 'es2015', cssCodeSplit: true, chunkSizeWarningLimit: 1000, rollupOptions: { output: { // 手动分包 manualChunks: { // Vue 生态 'vue-vendor': ['vue', 'vue-router', 'pinia'], // UI 组件库 'ui-vendor': ['ant-design-vue', 'ele-admin-pro'], // 工具库 'utils-vendor': ['lodash-es', 'dayjs', 'crypto-js', 'js-md5'], // 图表库 'charts-vendor': ['echarts', 'vue-echarts', 'echarts-wordcloud'], // 编辑器 'editor-vendor': ['tinymce', 'bytemd', 'md-editor-v3'], // 文件处理 'file-vendor': ['xlsx', 'exceljs', 'file-saver', 'ali-oss'] }, // 文件命名 chunkFileNames: (chunkInfo) => { const facadeModuleId = chunkInfo.facadeModuleId ? chunkInfo.facadeModuleId.split('/').pop().replace(/\.\w+$/, '') : 'chunk'; return `js/${facadeModuleId}-[hash].js`; }, assetFileNames: (assetInfo) => { const info = assetInfo.name.split('.'); const ext = info[info.length - 1]; if (/\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/i.test(assetInfo.name)) { return `media/[name]-[hash].${ext}`; } if (/\.(png|jpe?g|gif|svg)(\?.*)?$/.test(assetInfo.name)) { return `images/[name]-[hash].${ext}`; } if (/\.(woff2?|eot|ttf|otf)(\?.*)?$/i.test(assetInfo.name)) { return `fonts/[name]-[hash].${ext}`; } return `assets/[name]-[hash].${ext}`; } } }, // 压缩配置 minify: 'terser', terserOptions: { compress: { drop_console: true, drop_debugger: true, pure_funcs: ['console.log'] } } } }; });