index.ts 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. import type { PluginOption } from 'vite';
  2. import type {
  3. ApplicationPluginOptions,
  4. CommonPluginOptions,
  5. ConditionPlugin,
  6. LibraryPluginOptions,
  7. } from '../typing';
  8. import { join } from 'node:path';
  9. import { getPackage, getPackages } from '@vben/node-utils';
  10. import viteVueI18nPlugin from '@intlify/unplugin-vue-i18n/vite';
  11. import viteVue from '@vitejs/plugin-vue';
  12. import viteVueJsx from '@vitejs/plugin-vue-jsx';
  13. import { visualizer as viteVisualizerPlugin } from 'rollup-plugin-visualizer';
  14. import viteTurboConsolePlugin from 'unplugin-turbo-console/vite';
  15. import viteCompressPlugin from 'vite-plugin-compression';
  16. import viteDtsPlugin from 'vite-plugin-dts';
  17. import { createHtmlPlugin as viteHtmlPlugin } from 'vite-plugin-html';
  18. import { libInjectCss as viteLibInjectCss } from 'vite-plugin-lib-inject-css';
  19. import { VitePWA } from 'vite-plugin-pwa';
  20. import viteVueDevTools from 'vite-plugin-vue-devtools';
  21. import { viteExtraAppConfigPlugin } from './extra-app-config';
  22. import { viteImportMapPlugin } from './importmap';
  23. import { viteInjectAppLoadingPlugin } from './inject-app-loading';
  24. import { viteMetadataPlugin } from './inject-metadata';
  25. import { viteLicensePlugin } from './license';
  26. /**
  27. * 获取条件成立的 vite 插件
  28. * @param conditionPlugins
  29. */
  30. async function loadConditionPlugins(conditionPlugins: ConditionPlugin[]) {
  31. const plugins: PluginOption[] = [];
  32. for (const conditionPlugin of conditionPlugins) {
  33. if (conditionPlugin.condition) {
  34. const realPlugins = await conditionPlugin.plugins();
  35. plugins.push(...realPlugins);
  36. }
  37. }
  38. return plugins.flat();
  39. }
  40. /**
  41. * 根据条件获取通用的vite插件
  42. */
  43. async function loadCommonPlugins(
  44. options: CommonPluginOptions,
  45. ): Promise<ConditionPlugin[]> {
  46. const { devtools, injectMetadata, isBuild, visualizer } = options;
  47. return [
  48. {
  49. condition: true,
  50. plugins: () => [
  51. viteVue({
  52. script: {
  53. defineModel: true,
  54. // propsDestructure: true,
  55. },
  56. }),
  57. viteVueJsx(),
  58. ],
  59. },
  60. {
  61. condition: !isBuild && devtools,
  62. plugins: () => [viteVueDevTools()],
  63. },
  64. {
  65. condition: injectMetadata,
  66. plugins: async () => [await viteMetadataPlugin()],
  67. },
  68. {
  69. condition: isBuild && !!visualizer,
  70. plugins: () => [<PluginOption>viteVisualizerPlugin({
  71. filename: './node_modules/.cache/visualizer/stats.html',
  72. gzipSize: true,
  73. open: true,
  74. })],
  75. },
  76. ];
  77. }
  78. /**
  79. * 根据条件获取应用类型的vite插件
  80. */
  81. async function loadApplicationPlugins(
  82. options: ApplicationPluginOptions,
  83. ): Promise<PluginOption[]> {
  84. // 单独取,否则commonOptions拿不到
  85. const isBuild = options.isBuild;
  86. const env = options.env;
  87. const {
  88. compress,
  89. compressTypes,
  90. extraAppConfig,
  91. html,
  92. i18n,
  93. importmap,
  94. importmapOptions,
  95. injectAppLoading,
  96. license,
  97. pwa,
  98. pwaOptions,
  99. turboConsole,
  100. ...commonOptions
  101. } = options;
  102. const commonPlugins = await loadCommonPlugins(commonOptions);
  103. return await loadConditionPlugins([
  104. ...commonPlugins,
  105. {
  106. condition: i18n,
  107. plugins: async () => {
  108. const { packages } = await getPackages();
  109. const pkg = await getPackage('@vben-core/locales');
  110. const include: string[] = [
  111. `${join(pkg?.dir ?? '', isBuild ? 'dist' : 'src', 'langs')}/*.yaml`,
  112. ];
  113. // 加载所有应用的国际化文件
  114. for (const { dir, relativeDir } of packages) {
  115. if (
  116. // 排除非应用目录
  117. !relativeDir.startsWith('apps') ||
  118. // 排除mock目录
  119. relativeDir.includes('backend-mock')
  120. ) {
  121. continue;
  122. }
  123. include.push(`${join(dir, 'src', 'locales', 'langs')}/*.yaml`);
  124. }
  125. return [
  126. viteVueI18nPlugin({
  127. compositionOnly: true,
  128. fullInstall: true,
  129. include,
  130. runtimeOnly: true,
  131. }),
  132. ];
  133. },
  134. },
  135. {
  136. condition: injectAppLoading,
  137. plugins: async () => [await viteInjectAppLoadingPlugin(!!isBuild, env)],
  138. },
  139. {
  140. condition: license,
  141. plugins: async () => [await viteLicensePlugin()],
  142. },
  143. {
  144. condition: pwa,
  145. plugins: () =>
  146. VitePWA({
  147. devOptions: {
  148. enabled: true,
  149. type: 'module',
  150. },
  151. injectRegister: false,
  152. workbox: {
  153. globPatterns: [],
  154. },
  155. ...pwaOptions,
  156. manifest: {
  157. display: 'standalone',
  158. start_url: '/',
  159. theme_color: '#ffffff',
  160. ...pwaOptions?.manifest,
  161. },
  162. }),
  163. },
  164. {
  165. condition: isBuild && !!compress,
  166. plugins: () => {
  167. const compressPlugins: PluginOption[] = [];
  168. if (compressTypes?.includes('brotli')) {
  169. compressPlugins.push(
  170. viteCompressPlugin({ deleteOriginFile: false, ext: '.br' }),
  171. );
  172. }
  173. if (compressTypes?.includes('gzip')) {
  174. compressPlugins.push(
  175. viteCompressPlugin({ deleteOriginFile: false, ext: '.gz' }),
  176. );
  177. }
  178. return compressPlugins;
  179. },
  180. },
  181. {
  182. condition: !!html,
  183. plugins: () => [viteHtmlPlugin({ minify: true })],
  184. },
  185. {
  186. condition: isBuild && importmap,
  187. plugins: () => {
  188. return [viteImportMapPlugin(importmapOptions)];
  189. },
  190. },
  191. {
  192. condition: isBuild && extraAppConfig,
  193. plugins: async () => [
  194. await viteExtraAppConfigPlugin({ isBuild: true, root: process.cwd() }),
  195. ],
  196. },
  197. {
  198. condition: !isBuild && !!turboConsole,
  199. plugins: () => [viteTurboConsolePlugin()],
  200. },
  201. ]);
  202. }
  203. /**
  204. * 根据条件获取库类型的vite插件
  205. */
  206. async function loadLibraryPlugins(
  207. options: LibraryPluginOptions,
  208. ): Promise<PluginOption[]> {
  209. // 单独取,否则commonOptions拿不到
  210. const isBuild = options.isBuild;
  211. const { dts, injectLibCss, ...commonOptions } = options;
  212. const commonPlugins = await loadCommonPlugins(commonOptions);
  213. return await loadConditionPlugins([
  214. ...commonPlugins,
  215. {
  216. condition: isBuild && !!dts,
  217. plugins: () => [viteDtsPlugin({ logLevel: 'error' })],
  218. },
  219. {
  220. condition: injectLibCss,
  221. plugins: () => [viteLibInjectCss()],
  222. },
  223. ]);
  224. }
  225. export {
  226. loadApplicationPlugins,
  227. loadLibraryPlugins,
  228. viteCompressPlugin,
  229. viteDtsPlugin,
  230. viteHtmlPlugin,
  231. viteTurboConsolePlugin,
  232. viteVisualizerPlugin,
  233. };