Files
ogame-vue-ts/vite.config.ts
coolxitech 3410eeda19 feat(pwa): 集成 PWA 支持并配置离线缓存策略
- 添加 vite-plugin-pwa 插件依赖
- 配置应用清单(manifest)支持全屏模式
- 设置工作箱(workbox)缓存静态资源
- 实现图片和音频资源的运行时缓存
- 调整缓存大小限制至 5MB 以适应游戏资源
- 更新构建时间戳
2025-12-15 21:23:15 +08:00

122 lines
4.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import tailwindcss from '@tailwindcss/vite'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import { VitePWA } from 'vite-plugin-pwa'
import pkg from './package.json'
const __dirname = path.dirname(fileURLToPath(import.meta.url))
export default defineConfig(async () => {
const plugins = [
vue(),
tailwindcss(),
VitePWA({
registerType: 'autoUpdate',
manifest: {
name: pkg.name,
short_name: pkg.title,
description: '一款现代化 OGame 太空策略游戏',
theme_color: '#000000',
background_color: '#000000',
display: 'fullscreen',
orientation: 'any',
icons: [
{
src: 'logo.svg',
sizes: 'any',
type: 'image/svg+xml',
purpose: 'any',
},
],
},
workbox: {
// 关键:确保缓存了 dist 目录下所有的 JS, CSS, HTML 和 媒体文件
globPatterns: ['docs/*.{js,css,html,ico,png,svg,mp3,wav,json}'],
// 如果你的游戏资源(如音效或贴图)较大,请根据需要调大这个阈值(默认 2MB
// 这里设置为 5MB
maximumFileSizeToCacheInBytes: 5 * 1024 * 1024,
// 离线策略优化:对于游戏,我们希望即使在离线状态下,
// 所有的资源都能立刻从缓存加载,而不是去请求网络
runtimeCaching: [
{
urlPattern: ({ request }) => request.destination === 'image' || request.destination === 'audio',
handler: 'CacheFirst', // 优先使用缓存
options: {
cacheName: 'game-assets',
expiration: {
maxEntries: 100,
maxAgeSeconds: 30 * 24 * 60 * 60, // 缓存 30 天
},
},
},
],
}
})
];
// 只在 ELECTRON_BUILD 环境变量存在时才加载 Electron 插件
if (process.env.ELECTRON_BUILD) {
// @ts-ignore - 动态导入 electron 插件
const { default: electron } = await import('vite-plugin-electron/simple')
const electronPlugins = await electron({
main: {
entry: 'electron/main.ts',
},
renderer: {},
})
plugins.push(...electronPlugins)
}
return {
base: './',
build: {
outDir: 'docs',
sourcemap: false,
cssCodeSplit: true,
chunkSizeWarningLimit: 1000,
rollupOptions: {
output: {
manualChunks(id: string) {
// Vue 核心框架
if (id.includes('node_modules/vue/') || id.includes('node_modules/@vue/')) return 'vendor-vue-core'
// Vue 生态
if (id.includes('node_modules/vue-router')) return 'vendor-vue-router'
if (id.includes('node_modules/pinia')) return 'vendor-pinia'
// UI 组件库
if (id.includes('node_modules/reka-ui')) return 'vendor-reka-ui'
if (id.includes('node_modules/@vueuse/core')) return 'vendor-vueuse'
if (id.includes('node_modules/lucide-vue-next')) return 'vendor-icons'
// 工具库
if (id.includes('node_modules/crypto-js')) return 'vendor-crypto'
if (id.includes('node_modules/file-saver')) return 'vendor-utils'
if (id.includes('node_modules/clsx') || id.includes('node_modules/tailwind-merge')) return 'vendor-utils'
// Tailwind CSS
if (id.includes('node_modules/@tailwindcss') || id.includes('node_modules/tailwindcss')) return 'vendor-tailwind'
// 游戏逻辑模块
if (id.includes('/src/logic/')) return 'game-logic'
// 配置和类型
if (id.includes('/src/config/') || id.includes('/src/types/')) return 'game-config'
// 本地化
if (id.includes('/src/locales/')) return 'game-i18n'
// 其他 node_modules 依赖
if (id.includes('node_modules/')) return 'vendor-others'
},
// 优化输出文件名
chunkFileNames: 'assets/[name]-[hash].js',
entryFileNames: 'assets/[name]-[hash].js',
assetFileNames: 'assets/[name]-[hash].[ext]'
}
}
},
plugins,
resolve: { alias: { '@': path.resolve(__dirname, './src') } },
// 优化依赖预构建
optimizeDeps: { include: ['vue', 'vue-router', 'pinia', 'reka-ui', '@vueuse/core', 'lucide-vue-next', 'crypto-js', 'file-saver'] }
}
})