dramaling-app/apps/web/vite.config.ts

190 lines
5.0 KiB
TypeScript

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { VitePWA } from 'vite-plugin-pwa'
import Components from 'unplugin-vue-components/vite'
import AutoImport from 'unplugin-auto-import/vite'
import { quasar, transformAssetUrls } from '@quasar/vite-plugin'
import path from 'path'
export default defineConfig({
plugins: [
vue({
template: { transformAssetUrls }
}),
quasar({
// sassVariables: 'src/assets/styles/quasar-variables.sass'
}),
Components({
resolvers: [
(componentName) => {
if (componentName.startsWith('Q'))
return { name: componentName, from: 'quasar' }
}
],
dts: true,
dirs: ['src/components'],
extensions: ['vue'],
deep: true
}),
AutoImport({
imports: [
'vue',
'vue-router',
'pinia',
{
'quasar': ['useQuasar', '$q', 'Notify', 'Loading', 'Dialog'],
'@vueuse/core': ['useLocalStorage', 'useSessionStorage', 'useFetch']
}
],
dts: true,
dirs: ['src/composables', 'src/stores'],
vueTemplate: true
}),
VitePWA({
registerType: 'autoUpdate',
workbox: {
globPatterns: ['**/*.{js,css,html,ico,png,svg,woff2}'],
skipWaiting: true,
clientsClaim: true,
runtimeCaching: [
{
urlPattern: /^https:\/\/api\..*/i,
handler: 'NetworkFirst',
options: {
cacheName: 'api-cache',
networkTimeoutSeconds: 10,
expiration: {
maxEntries: 50,
maxAgeSeconds: 5 * 60, // 5 minutes
},
cacheableResponse: {
statuses: [0, 200],
},
},
},
{
urlPattern: /\.(?:png|gif|jpg|jpeg|svg|webp)$/,
handler: 'CacheFirst',
options: {
cacheName: 'images-cache',
expiration: {
maxEntries: 100,
maxAgeSeconds: 30 * 24 * 60 * 60, // 30 days
},
},
},
],
},
manifest: {
name: 'Drama Ling - 戲劇式語言學習',
short_name: 'Drama Ling',
description: '透過情境對話和互動練習學習語言的 AI 驅動應用程式',
theme_color: '#00E5CC',
background_color: '#1A1A1A',
display: 'standalone',
orientation: 'portrait',
scope: '/',
start_url: '/learning',
categories: ['education', 'productivity'],
lang: 'zh-TW',
screenshots: [
{
src: '/icons/screenshot-wide.png',
sizes: '1280x720',
type: 'image/png',
form_factor: 'wide',
label: 'Drama Ling 學習介面'
}
],
shortcuts: [
{
name: '詞彙學習',
short_name: '詞彙',
description: '開始詞彙練習',
url: '/learning/vocabulary',
icons: [{ src: '/icons/shortcut-vocabulary.png', sizes: '96x96' }]
},
{
name: '智能複習',
short_name: '複習',
description: '進行智能複習',
url: '/learning/vocabulary/review',
icons: [{ src: '/icons/shortcut-review.png', sizes: '96x96' }]
}
],
icons: [
{
src: '/favicon.svg',
sizes: 'any',
type: 'image/svg+xml'
},
{
src: '/icons/icon-192x192.svg',
sizes: '192x192',
type: 'image/svg+xml'
},
{
src: '/icons/icon-512x512.svg',
sizes: '512x512',
type: 'image/svg+xml'
}
]
},
devOptions: {
enabled: false, // 只在生產環境啟用
type: 'module',
navigateFallback: 'index.html'
}
})
],
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
'~': path.resolve(__dirname, 'src'),
'@components': path.resolve(__dirname, 'src/components'),
'@modules': path.resolve(__dirname, 'src/modules'),
'@stores': path.resolve(__dirname, 'src/stores'),
'@services': path.resolve(__dirname, 'src/services'),
'@utils': path.resolve(__dirname, 'src/utils'),
'@assets': path.resolve(__dirname, 'src/assets')
}
},
css: {
preprocessorOptions: {
scss: {
additionalData: `@import "@/assets/styles/variables.scss";`
}
}
},
build: {
target: 'es2020',
rollupOptions: {
output: {
manualChunks: {
'vue-vendor': ['vue', 'vue-router', 'pinia'],
'quasar-vendor': ['quasar'],
'utils-vendor': ['axios', 'lodash-es', 'dayjs', '@vueuse/core'],
'validation-vendor': ['vee-validate', 'yup']
}
}
}
},
server: {
host: '0.0.0.0',
port: 3000,
proxy: {
'/api': {
target: 'http://localhost:5000',
changeOrigin: true
}
}
}
})