vite.config.ts 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  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://192.168.10.140:9089',
  44. changeOrigin: true,
  45. ws: true,
  46. rewrite: (path) => path.replace(/^\/api/, ''),
  47. secure: false
  48. }
  49. }
  50. },
  51. plugins: [
  52. vue(),
  53. vueJsx(),
  54. Unocss({
  55. configFile: './uno.config.ts'
  56. }),
  57. VueDevTools(),
  58. // 允许 setup 语法糖上添加组件名属性
  59. vueSetupExtend(),
  60. // 打包后生产依赖大小分析
  61. visualizer({
  62. filename: './node_modules/.cache/visualizer/stats.html',
  63. open: true,
  64. gzipSize: true,
  65. brotliSize: true
  66. }),
  67. AutoImport({
  68. imports: ['vue', 'vue-router'],
  69. resolvers: [ElementPlusResolver()],
  70. dts: 'src/typings/auto-imports.d.ts',
  71. eslintrc: {
  72. enabled: true,
  73. filepath: './.eslintrc-auto-import.json'
  74. }
  75. }),
  76. // 注入模板数据
  77. createHtmlPlugin({
  78. inject: {
  79. data: {
  80. title: env.VITE_GLOB_APP_TITLE
  81. }
  82. }
  83. }),
  84. // svg 图标
  85. createSvgIconsPlugin({
  86. iconDirs: [resolve(root, 'src/assets/icons')],
  87. symbolId: 'icon-[dir]-[name]'
  88. }),
  89. Components({
  90. extensions: ['vue', 'tsx', 'md'],
  91. globs: ['src/components/*/*.vue', 'src/components/*/*.tsx'],
  92. include: [/\.vue$/, /\.vue\?vue/, /\.md$/, /\.[tj]sx?$/],
  93. resolvers: [
  94. ElementPlusResolver({
  95. importStyle: 'sass'
  96. })
  97. ],
  98. dts: 'src/typings/components.d.ts'
  99. }),
  100. // 图片压缩
  101. viteImagemin({
  102. gifsicle: {
  103. optimizationLevel: 7,
  104. interlaced: false
  105. },
  106. optipng: {
  107. optimizationLevel: 7
  108. },
  109. mozjpeg: {
  110. quality: 80
  111. },
  112. pngquant: {
  113. quality: [0.8, 0.9],
  114. speed: 4
  115. },
  116. svgo: {
  117. plugins: [
  118. {
  119. name: 'removeViewBox'
  120. },
  121. {
  122. name: 'removeEmptyAttrs'
  123. }
  124. ]
  125. }
  126. }),
  127. // gzip 压缩资源
  128. viteCompression({
  129. // 压缩算法使用 gzip
  130. algorithm: 'gzip',
  131. // 压缩后的文件后缀
  132. ext: '.gz',
  133. // 是否删除原始文件
  134. deleteOriginFile: false,
  135. // 资源文件大于1024B=1kB时会被压缩
  136. threshold: 1024
  137. }),
  138. // 生产环境 brotli 压缩资源
  139. viteCompression({
  140. // 压缩算法使用 brotli
  141. algorithm: 'brotliCompress',
  142. // 压缩后的文件后缀
  143. ext: '.br',
  144. // 是否删除原始文件
  145. deleteOriginFile: false,
  146. // 资源文件大于1024B=1kB时会被压缩
  147. threshold: 1024
  148. })
  149. ],
  150. build: {
  151. rollupOptions: {
  152. output: {
  153. // 打包分类
  154. chunkFileNames: 'assets/js/[name]-[hash].js',
  155. entryFileNames: 'assets/js/[name]-[hash].js',
  156. assetFileNames: 'assets/[ext]/[name]-[hash].[ext]',
  157. // 分包策略
  158. manualChunks: {
  159. vue: ['vue'],
  160. 'element-plus-icons': ['@element-plus/icons-vue'],
  161. 'vue-router': ['vue-router'],
  162. 'element-plus': ['element-plus'],
  163. 'vue-i18n': ['vue-i18n']
  164. },
  165. // 打包后的文件夹名称生成规则-->解决部分静态服务器无法正常返回_plugin-vue_export-helper文件
  166. sanitizeFileName(name) {
  167. const match = /^[a-z]:/i.exec(name)
  168. const driveLetter = match ? match[0] : ''
  169. return (
  170. driveLetter +
  171. name
  172. .substring(driveLetter.length)
  173. // eslint-disable-next-line no-control-regex
  174. .replace(/[\x00-\x1F\x7F<>*#"{}|^[\]`;?:&=+$,]/g, '')
  175. )
  176. }
  177. }
  178. }
  179. }
  180. }
  181. })