vite.config.ts 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. import { fileURLToPath, URL } from 'node:url'
  2. import { defineConfig, loadEnv } from 'vite'
  3. import vue from '@vitejs/plugin-vue'
  4. import vueJsx from '@vitejs/plugin-vue-jsx'
  5. import AutoImport from 'unplugin-auto-import/vite'
  6. import Components from 'unplugin-vue-components/vite'
  7. import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
  8. import viteCompression from 'vite-plugin-compression'
  9. import vueSetupExtend from 'vite-plugin-vue-setup-extend'
  10. import viteImagemin from 'vite-plugin-imagemin'
  11. import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
  12. import { visualizer } from 'rollup-plugin-visualizer'
  13. import Unocss from 'unocss/vite'
  14. import VueDevTools from 'vite-plugin-vue-devtools'
  15. import { resolve } from 'path'
  16. import { createHtmlPlugin } from 'vite-plugin-html'
  17. // https://vitejs.dev/config/
  18. export default defineConfig(({ mode }) => {
  19. let root = process.cwd()
  20. const env = loadEnv(mode, root)
  21. return {
  22. base: env.VITE_PUBLIC_PATH,
  23. root,
  24. resolve: {
  25. alias: {
  26. '@': fileURLToPath(new URL('./src', import.meta.url))
  27. }
  28. },
  29. css: {
  30. preprocessorOptions: {
  31. scss: {
  32. additionalData: '@use "@/styles/element/index.scss";',
  33. api: 'modern-compiler',
  34. },
  35. },
  36. },
  37. server: {
  38. host: '0.0.0.0',
  39. port: 3200,
  40. open: true,
  41. proxy: {
  42. '/api': {
  43. // target: 'http://localhost:9089',
  44. target: 'https://demo.lowflow.vip/api',
  45. changeOrigin: true,
  46. ws: true,
  47. rewrite: (path) => path.replace(/^\/api/, ''),
  48. secure: false
  49. }
  50. }
  51. },
  52. plugins: [
  53. vue(),
  54. vueJsx(),
  55. Unocss({
  56. configFile: './uno.config.ts'
  57. }),
  58. VueDevTools(),
  59. // 允许 setup 语法糖上添加组件名属性
  60. vueSetupExtend(),
  61. // 打包后生产依赖大小分析
  62. visualizer({
  63. filename: './node_modules/.cache/visualizer/stats.html',
  64. open: true,
  65. gzipSize: true,
  66. brotliSize: true
  67. }),
  68. AutoImport({
  69. imports: ['vue', 'vue-router'],
  70. resolvers: [ElementPlusResolver()],
  71. dts: 'src/typings/auto-imports.d.ts',
  72. eslintrc: {
  73. enabled: true,
  74. filepath: './.eslintrc-auto-import.json'
  75. }
  76. }),
  77. // 注入模板数据
  78. createHtmlPlugin({
  79. inject: {
  80. data: {
  81. title: env.VITE_GLOB_APP_TITLE
  82. }
  83. }
  84. }),
  85. // svg 图标
  86. createSvgIconsPlugin({
  87. iconDirs: [resolve(root, 'src/assets/icons')],
  88. symbolId: 'icon-[dir]-[name]'
  89. }),
  90. Components({
  91. extensions: ['vue', 'tsx', 'md'],
  92. globs: ['src/components/*/*.vue', 'src/components/*/*.tsx'],
  93. include: [/\.vue$/, /\.vue\?vue/, /\.md$/, /\.[tj]sx?$/],
  94. resolvers: [
  95. ElementPlusResolver({
  96. importStyle: 'sass'
  97. })
  98. ],
  99. dts: 'src/typings/components.d.ts'
  100. }),
  101. // 图片压缩
  102. viteImagemin({
  103. gifsicle: {
  104. optimizationLevel: 7,
  105. interlaced: false
  106. },
  107. optipng: {
  108. optimizationLevel: 7
  109. },
  110. mozjpeg: {
  111. quality: 80
  112. },
  113. pngquant: {
  114. quality: [0.8, 0.9],
  115. speed: 4
  116. },
  117. svgo: {
  118. plugins: [
  119. {
  120. name: 'removeViewBox'
  121. },
  122. {
  123. name: 'removeEmptyAttrs'
  124. }
  125. ]
  126. }
  127. }),
  128. // gzip 压缩资源
  129. viteCompression({
  130. // 压缩算法使用 gzip
  131. algorithm: 'gzip',
  132. // 压缩后的文件后缀
  133. ext: '.gz',
  134. // 是否删除原始文件
  135. deleteOriginFile: false,
  136. // 资源文件大于1024B=1kB时会被压缩
  137. threshold: 1024
  138. }),
  139. // 生产环境 brotli 压缩资源
  140. viteCompression({
  141. // 压缩算法使用 brotli
  142. algorithm: 'brotliCompress',
  143. // 压缩后的文件后缀
  144. ext: '.br',
  145. // 是否删除原始文件
  146. deleteOriginFile: false,
  147. // 资源文件大于1024B=1kB时会被压缩
  148. threshold: 1024
  149. })
  150. ],
  151. build: {
  152. rollupOptions: {
  153. output: {
  154. // 打包分类
  155. chunkFileNames: 'assets/js/[name]-[hash].js',
  156. entryFileNames: 'assets/js/[name]-[hash].js',
  157. assetFileNames: 'assets/[ext]/[name]-[hash].[ext]',
  158. // 分包策略
  159. manualChunks: {
  160. vue: ['vue'],
  161. 'element-plus-icons': ['@element-plus/icons-vue'],
  162. 'vue-router': ['vue-router'],
  163. 'element-plus': ['element-plus'],
  164. 'vue-i18n': ['vue-i18n']
  165. },
  166. // 打包后的文件夹名称生成规则-->解决部分静态服务器无法正常返回_plugin-vue_export-helper文件
  167. sanitizeFileName(name) {
  168. const match = /^[a-z]:/i.exec(name)
  169. const driveLetter = match ? match[0] : ''
  170. return (
  171. driveLetter +
  172. name
  173. .substring(driveLetter.length)
  174. // eslint-disable-next-line no-control-regex
  175. .replace(/[\x00-\x1F\x7F<>*#"{}|^[\]`;?:&=+$,]/g, '')
  176. )
  177. }
  178. }
  179. }
  180. }
  181. }
  182. })