pwa.ts 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. /**
  2. * PWA 插件配置 - 适配按需加载
  3. */
  4. import { VitePWA } from 'vite-plugin-pwa';
  5. import type { VitePWAOptions } from 'vite-plugin-pwa';
  6. import type { PluginOption } from 'vite';
  7. export function configPwaPlugin(isBuild: boolean): PluginOption | PluginOption[] {
  8. if (!isBuild) {
  9. console.log('非生产环境不启用 PWA 插件!');
  10. return [];
  11. }
  12. const pwaOptions: Partial<VitePWAOptions> = {
  13. registerType: 'manual',
  14. injectRegister: 'inline', // 将 Service Worker 注册代码内联到 HTML 中,避免缓存问题
  15. includeAssets: ['favicon.ico', 'logo.png'],
  16. manifest: {
  17. name: 'JeecgBoot',
  18. short_name: 'Jeecg',
  19. theme_color: '#ffffff',
  20. icons: [
  21. {
  22. src: '/logo.png',
  23. sizes: '192x192',
  24. type: 'image/png',
  25. },
  26. {
  27. src: '/logo.png',
  28. sizes: '512x512',
  29. type: 'image/png',
  30. },
  31. ],
  32. },
  33. workbox: {
  34. maximumFileSizeToCacheInBytes: 10 * 1024 * 1024, // 10MB
  35. cleanupOutdatedCaches: true,
  36. // 预缓存:只缓存关键资源,不预缓存路由组件 CSS/JS(避免登录页加载全部资源)
  37. globPatterns: [
  38. 'index.html', // 必须预缓存(避免 non-precached-url 错误)
  39. 'manifest.webmanifest',
  40. 'assets/index-*.css', // 仅入口 CSS
  41. 'favicon.ico',
  42. 'logo.png',
  43. 'js/index-*.js',
  44. 'js/*-vendor-*.js',
  45. ],
  46. // 不使用导航回退功能
  47. navigateFallback: undefined,
  48. // 运行时缓存:按需加载的资源
  49. runtimeCaching: [
  50. {
  51. urlPattern: /\/js\/.*\.js$/i,
  52. handler: 'NetworkFirst',
  53. options: {
  54. cacheName: 'js-chunks-cache',
  55. networkTimeoutSeconds: 3,
  56. expiration: {
  57. maxEntries: 100,
  58. maxAgeSeconds: 60 * 60 * 24 * 7, // 7天
  59. },
  60. cacheableResponse: {
  61. statuses: [0, 200],
  62. },
  63. },
  64. },
  65. {
  66. urlPattern: /\/assets\/.*\.css$/i,
  67. handler: 'CacheFirst',
  68. options: {
  69. cacheName: 'css-cache',
  70. expiration: {
  71. maxEntries: 50,
  72. maxAgeSeconds: 60 * 60 * 24 * 30, // 30天
  73. },
  74. cacheableResponse: {
  75. statuses: [0, 200],
  76. },
  77. },
  78. },
  79. // Google Fonts
  80. {
  81. urlPattern: /^https:\/\/fonts\.googleapis\.com\/.*/i,
  82. handler: 'CacheFirst',
  83. options: {
  84. cacheName: 'google-fonts-cache',
  85. expiration: {
  86. maxEntries: 10,
  87. maxAgeSeconds: 60 * 60 * 24 * 365,
  88. },
  89. cacheableResponse: {
  90. statuses: [0, 200],
  91. },
  92. },
  93. },
  94. // 图片资源
  95. {
  96. urlPattern: /\.(?:png|jpg|jpeg|svg|gif|webp)$/,
  97. handler: 'CacheFirst',
  98. options: {
  99. cacheName: 'image-cache',
  100. expiration: {
  101. maxEntries: 100,
  102. maxAgeSeconds: 60 * 60 * 24 * 30,
  103. },
  104. },
  105. },
  106. // API 请求
  107. {
  108. urlPattern: /\/api\/.*/i,
  109. handler: 'NetworkFirst',
  110. options: {
  111. cacheName: 'api-cache',
  112. networkTimeoutSeconds: 10,
  113. expiration: {
  114. maxEntries: 50,
  115. maxAgeSeconds: 60 * 5,
  116. },
  117. cacheableResponse: {
  118. statuses: [0, 200],
  119. },
  120. },
  121. },
  122. ],
  123. // 启用立即更新:新 SW 立即激活并接管页面
  124. skipWaiting: true,
  125. clientsClaim: true,
  126. },
  127. devOptions: {
  128. enabled: false,
  129. },
  130. };
  131. return VitePWA(pwaOptions);
  132. }