import { fileURLToPath, URL } from 'node:url' import type { ProxyOptions } from 'vite' import { defineConfig, loadEnv } from 'vite' import { createSvgIconsPlugin } from 'vite-plugin-svg-icons' import compressPlugin from 'vite-plugin-compression' import vue from '@vitejs/plugin-vue' import { createHtmlPlugin } from 'vite-plugin-html'; import DefineOptions from 'unplugin-vue-define-options/vite' import { visualizer } from 'rollup-plugin-visualizer'; import path from 'path' import dayjs from 'dayjs' import fs from 'fs' import archiver from 'archiver'; import { mockDevServerPlugin } from 'vite-plugin-mock-dev-server' const timeStr = dayjs().format('YYYY-MM-DD-HH-mm-ss') const envDir = './env' // https://vitejs.dev/config/ export default defineConfig(({ mode }) => { const ENV = loadEnv(mode, envDir) const prefix = process.env.VITE_DYNAMIC_PREFIX || ENV.VITE_BASE_PATH; const proxyConf: Record = {} proxyConf['/ai-review/api'] = { target: 'https://finyxdev.datacubeworld.com', changeOrigin: true, rewrite: (path) => path.replace(ENV.VITE_BASE_PATH, '/') } proxyConf['/ai-doc/api'] = { target: 'https://finyxdev.datacubeworld.com', changeOrigin: true, rewrite: (path) => path.replace(ENV.VITE_BASE_PATH, '/') } proxyConf['/finyx-bot/api'] = { target: 'https://finyxdev.datacubeworld.com', changeOrigin: true, rewrite: (path) => path.replace(ENV.VITE_BASE_PATH, '/') } // 登录使用dada proxyConf['/dada'] = { target: 'https://finyxdev.datacubeworld.com', changeOrigin: true, rewrite: (path) => path.replace(ENV.VITE_BASE_PATH, '/') } return { preflight: false, lintOnSave: false, base: prefix, envDir: envDir, plugins: [ vue(), DefineOptions(), // compressPlugin({ // threshold: 3072, //3KB 仅压缩文件大小大于此阈值的文件 // deleteOriginFile: false, // 是否删除原始文件 // }), compressPlugin({ algorithm: "gzip", // 指定压缩算法为gzip,[ 'gzip' , 'brotliCompress' ,'deflate' , 'deflateRaw'] ext: ".gz", // 指定压缩后的文件扩展名为.gz threshold: 10240, // 仅对文件大小大于threshold的文件进行压缩,默认为10KB deleteOriginFile: false, // 是否删除原始文件,默认为false filter: /\.(js|css|json|html|ico|svg)(\?.*)?$/i, // 匹配要压缩的文件的正则表达式,默认为匹配.js、.css、.json、.html、.ico和.svg文件 compressionOptions: { level: 9 }, // 指定gzip压缩级别,默认为9(最高级别) verbose: true, //是否在控制台输出压缩结果 disable: false, //是否禁用插件 }), // 注册所有的svg文件生成svg雪碧图 createSvgIconsPlugin({ iconDirs: [path.resolve(process.cwd(), "src/assets/icons")], //svg图片存放的目录 symbolId: "icon-[name]", // symbol的id inject: "body-last", // 插入的位置 customDomId: "__svg__icons__dom__" // svg的id }), visualizer({ open: true, //在默认用户代理中打开生成的文件 gzipSize: true, // 收集 gzip 大小并将其显示 brotliSize: true, // 收集 brotli 大小并将其显示 filename: "stats.html", // 分析图生成的文件名 }), createHtmlPlugin({ inject: { data: { buildTime: timeStr // 生成打包时间 } } }), { name: 'custom-plugin', closeBundle() { if(ENV.VITE_BUILD !== 'PRD') return console.log('开始打包中...') const sourceDir = `./dist`; // 需打包的目录 const outputPath = `./ui${timeStr}.zip`; // 输出路径 // 创建输出流 const output = fs.createWriteStream(outputPath); const archive = archiver('zip', { zlib: { level: 9 } }); // 递归添加目录内容 archive.directory(sourceDir, false); archive.pipe(output); // 完成事件 archive.finalize().then(() => { console.log(`打包完成: ${outputPath}`); }); } }, ENV.VITE_MOCK_DEV_SERVER === 'true' ? mockDevServerPlugin({ reload: false, prefix: '/ai-doc' }) : null, ], server: { cors: true, host: '0.0.0.0', port: Number(ENV.VITE_APP_PORT), strictPort: true, allowedHosts: ['frp.jczxw.cn'], proxy: proxyConf }, build: { sourcemap: false, // 根据环境变量决定是否开启Source Map minify: 'terser', // 启用 terser 压缩 terserOptions: { compress: { pure_funcs: ['console.log'], // 只删除 console.log //drop_console: true, // 删除所有 console drop_debugger: true, // 删除 debugger } }, outDir: `dist`, chunkSizeWarningLimit: 500, // 调整包的大小 rollupOptions: { output: { // manualChunks(id) { // if (id.includes('node_modules')) { // return id.toString().split('node_modules/')[1].split('/')[0].toString() // } // }, manualChunks: { vue: ['vue', 'vue-router'], lodash: ['lodash-es'], echarts: ['echarts'], elementPlus: ['element-plus','@element-plus/icons-vue'], moment: ['moment'], katex: ['katex'], mermaid: ['mermaid'], mdEditorV3:['md-editor-v3'] }, entryFileNames: 'assets/js/[name].[hash].js', // 用于命名代码拆分时创建的共享块的输出命名 chunkFileNames: 'assets/js/[name].[hash].js', // 用于输出静态资源的命名,[ext]表示文件扩展名 assetFileNames: 'assets/[ext]/[name].[hash].[ext]' } } }, resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) } } } })