vite.config.ts 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. import { defineConfig, loadEnv } from 'vite'
  2. import vue from '@vitejs/plugin-vue'
  3. import path from 'path'
  4. import { fileURLToPath } from 'url'
  5. import vueDevTools from 'vite-plugin-vue-devtools'
  6. import viteCompression from 'vite-plugin-compression'
  7. import Components from 'unplugin-vue-components/vite'
  8. import AutoImport from 'unplugin-auto-import/vite'
  9. import ElementPlus from 'unplugin-element-plus/vite'
  10. import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
  11. import tailwindcss from '@tailwindcss/vite'
  12. // import { visualizer } from 'rollup-plugin-visualizer'
  13. export default ({ mode }: { mode: string }) => {
  14. const root = process.cwd()
  15. const env = loadEnv(mode, root)
  16. const { VITE_VERSION, VITE_PORT, VITE_BASE_URL, VITE_API_URL, VITE_API_PROXY_URL } = env
  17. const isDev = mode === 'development'
  18. const isDockerBuild = mode === 'docker'
  19. const dropConsole = env.VITE_DROP_CONSOLE === 'true'
  20. console.log(`🚀 API_URL = ${VITE_API_URL}`)
  21. console.log(`🚀 VERSION = ${VITE_VERSION}`)
  22. return defineConfig({
  23. define: {
  24. __APP_VERSION__: JSON.stringify(VITE_VERSION)
  25. },
  26. base: VITE_BASE_URL,
  27. server: {
  28. port: Number(VITE_PORT),
  29. proxy: {
  30. '/api': {
  31. target: VITE_API_PROXY_URL,
  32. changeOrigin: true
  33. },
  34. // Web端接口代理 - 转发到后端 /api 前缀(与 /api 一致走本地 backend)
  35. '/web': {
  36. target: VITE_API_PROXY_URL,
  37. changeOrigin: true,
  38. rewrite: (path) => `/api${path}`
  39. },
  40. // 小程序端接口代理
  41. '/mini': {
  42. target: VITE_API_PROXY_URL,
  43. changeOrigin: true,
  44. rewrite: (path) => `/api${path}`
  45. }
  46. },
  47. host: true
  48. },
  49. // 路径别名
  50. resolve: {
  51. alias: {
  52. '@': fileURLToPath(new URL('./src', import.meta.url)),
  53. '@views': resolvePath('src/views'),
  54. '@imgs': resolvePath('src/assets/images'),
  55. '@icons': resolvePath('src/assets/icons'),
  56. '@utils': resolvePath('src/utils'),
  57. '@stores': resolvePath('src/store'),
  58. '@styles': resolvePath('src/assets/styles')
  59. }
  60. },
  61. build: {
  62. target: 'es2015',
  63. outDir: 'dist',
  64. chunkSizeWarningLimit: 2000,
  65. // docker 镜像构建用 esbuild,内存占用远低于 terser(避免 Docker 内 OOM)
  66. minify: isDockerBuild ? 'esbuild' : 'terser',
  67. ...(isDockerBuild
  68. ? {
  69. esbuild: dropConsole ? { drop: ['console', 'debugger'] } : undefined
  70. }
  71. : {
  72. terserOptions: {
  73. compress: {
  74. drop_console: dropConsole,
  75. drop_debugger: dropConsole
  76. }
  77. }
  78. }),
  79. rollupOptions: {
  80. input: {
  81. main: path.resolve(__dirname, 'index.html'),
  82. 'oa-fc-host': path.resolve(__dirname, 'oa-fc-host.html')
  83. }
  84. },
  85. dynamicImportVarsOptions: {
  86. warnOnError: true,
  87. exclude: [],
  88. include: ['src/views/**/*.vue']
  89. }
  90. },
  91. plugins: [
  92. vue(),
  93. tailwindcss(),
  94. // 自动按需导入 API
  95. AutoImport({
  96. imports: ['vue', 'vue-router', 'pinia', '@vueuse/core'],
  97. dts: 'src/types/import/auto-imports.d.ts',
  98. resolvers: [ElementPlusResolver()],
  99. eslintrc: {
  100. enabled: true,
  101. filepath: './.auto-import.json',
  102. globalsPropValue: true
  103. }
  104. }),
  105. // 自动按需导入组件
  106. Components({
  107. dts: 'src/types/import/components.d.ts',
  108. resolvers: [ElementPlusResolver()]
  109. }),
  110. // 按需定制主题配置
  111. ElementPlus({
  112. useSource: true
  113. }),
  114. // docker 构建跳过预压缩,减少峰值内存;交付镜像由 Nginx 直接托管静态资源
  115. ...(isDockerBuild
  116. ? []
  117. : [
  118. viteCompression({
  119. verbose: false,
  120. disable: false,
  121. algorithm: 'gzip',
  122. ext: '.gz',
  123. threshold: 10240,
  124. deleteOriginFile: false
  125. })
  126. ]),
  127. ...(isDev ? [vueDevTools()] : [])
  128. // 打包分析
  129. // visualizer({
  130. // open: true,
  131. // gzipSize: true,
  132. // brotliSize: true,
  133. // filename: 'dist/stats.html' // 分析图生成的文件名及路径
  134. // }),
  135. ],
  136. // 依赖预构建:避免运行时重复请求与转换,提升首次加载速度
  137. optimizeDeps: {
  138. include: [
  139. 'echarts/core',
  140. 'echarts/charts',
  141. 'echarts/components',
  142. 'echarts/renderers',
  143. 'xlsx',
  144. 'xgplayer',
  145. 'crypto-js',
  146. 'file-saver',
  147. 'vue-img-cutter',
  148. 'element-plus/es',
  149. 'element-plus/es/components/*/style/css',
  150. 'element-plus/es/components/*/style/index'
  151. ]
  152. },
  153. css: {
  154. preprocessorOptions: {
  155. // sass variable and mixin
  156. scss: {
  157. additionalData: `
  158. @use "@styles/core/el-light.scss" as *;
  159. @use "@styles/core/mixin.scss" as *;
  160. `
  161. }
  162. },
  163. postcss: {
  164. plugins: [
  165. {
  166. postcssPlugin: 'internal:charset-removal',
  167. AtRule: {
  168. charset: (atRule) => {
  169. if (atRule.name === 'charset') {
  170. atRule.remove()
  171. }
  172. }
  173. }
  174. }
  175. ]
  176. }
  177. }
  178. })
  179. }
  180. function resolvePath(paths: string) {
  181. return path.resolve(__dirname, paths)
  182. }