import wasm from 'vite-plugin-wasm' import topLevelAwait from 'vite-plugin-top-level-await' import glsl from 'vite-plugin-glsl' import { fileURLToPath } from 'url' // https://nuxt.com/docs/api/configuration/nuxt-config export default defineNuxtConfig({ compatibilityDate: '2026-01-30', future: { compatibilityVersion: 4 }, srcDir: 'app', serverDir: fileURLToPath(new URL('./server', import.meta.url)), dir: { public: fileURLToPath(new URL('./public', import.meta.url)) }, devtools: { enabled: process.env.NODE_ENV === 'development' }, devServer: { host: '0.0.0.0', // 允许局域网访问 port: 3000 }, modules: [ '@nuxtjs/tailwindcss', ...(process.env.NODE_ENV === 'development' || process.env.npm_lifecycle_event?.includes('lint') ? ['@nuxt/eslint'] : []) ], // 引入全局CSS css: [ '~/assets/css/variables.css', '~/assets/css/components.css', '~/assets/css/main.css', '~/assets/css/transitions.css', '~/assets/css/mobile-admin.css', '~/assets/css/print-fix.css', '~/assets/css/sf-pro-icons.css' ], // 配置运行时配置 runtimeConfig: { // 服务器私有键(不会暴露到客户端) jwtSecret: process.env.JWT_SECRET || 'your-secret-key', // Redis配置(可选) redisUrl: process.env.REDIS_URL || '', // 公共键(会暴露到客户端) public: { host: process.env.NUXT_PUBLIC_HOST || '', // 用于 CORS 和反向代理的主机名验证 apiBase: '/api', oauth: { github: !!process.env.GITHUB_CLIENT_ID, casdoor: !!process.env.CASDOOR_CLIENT_ID, google: !!process.env.GOOGLE_CLIENT_ID }, siteTitle: process.env.NUXT_PUBLIC_SITE_TITLE || '校园广播站点歌系统', siteLogo: process.env.NUXT_PUBLIC_SITE_LOGO || '', siteDescription: process.env.NUXT_PUBLIC_SITE_DESCRIPTION || '校园广播站点歌系统 - 让你的声音被听见', isNetlify: process.env.NETLIFY === 'true' } }, // 配置环境变量 app: { head: { title: process.env.NUXT_PUBLIC_SITE_TITLE || '校园广播站点歌系统', meta: [ { charset: 'utf-8' }, { name: 'viewport', content: 'width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover' }, { name: 'description', content: process.env.NUXT_PUBLIC_SITE_DESCRIPTION || '校园广播站点歌系统 - 让你的声音被听见' }, // 移动端优化 { name: 'theme-color', content: '#111111' }, { name: 'apple-mobile-web-app-capable', content: 'yes' }, { name: 'apple-mobile-web-app-status-bar-style', content: 'black-translucent' }, { name: 'apple-mobile-web-app-title', content: 'VoiceHub管理' }, { name: 'mobile-web-app-capable', content: 'yes' }, { name: 'format-detection', content: 'telephone=no' } ], link: [ { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }, // 优先加载常规字体,确保页面快速显示 { rel: 'preload', as: 'style', href: 'https://cdn.jsdelivr.net/npm/misans@4.1.0/lib/Normal/MiSans-Regular.min.css' }, { rel: 'stylesheet', href: 'https://cdn.jsdelivr.net/npm/misans@4.1.0/lib/Normal/MiSans-Regular.min.css' }, // 延迟加载其他字重,避免阻塞页面渲染 { rel: 'preload', as: 'style', href: 'https://cdn.jsdelivr.net/npm/misans@4.1.0/lib/Normal/MiSans-Medium.min.css', onload: "this.onload=null;this.rel='stylesheet'" }, { rel: 'preload', as: 'style', href: 'https://cdn.jsdelivr.net/npm/misans@4.1.0/lib/Normal/MiSans-Semibold.min.css', onload: "this.onload=null;this.rel='stylesheet'" }, { rel: 'preload', as: 'style', href: 'https://cdn.jsdelivr.net/npm/misans@4.1.0/lib/Normal/MiSans-Bold.min.css', onload: "this.onload=null;this.rel='stylesheet'" } ] } }, features: { inlineStyles: false }, // TypeScript配置 typescript: { strict: true }, // 服务器端配置 nitro: { preset: process.env.VERCEL ? 'vercel' : process.env.NETLIFY ? 'netlify' : process.env.NITRO_PRESET || 'node-server', // 增强错误处理和稳定性 experimental: { wasm: true, asyncContext: true }, timing: true, // 增加请求超时时间 routeRules: { // 完全禁用所有API路由的缓存,确保每次都请求数据库 '/api/**': { headers: { 'Cache-Control': 'no-cache, no-store, must-revalidate', Pragma: 'no-cache', Expires: '0', Connection: 'keep-alive' } }, // 静态资源文件缓存配置 '/_nuxt/**': { headers: { 'Cache-Control': 'public, max-age=31536000, immutable' } }, '/assets/**': { headers: { 'Cache-Control': 'public, max-age=31536000, immutable' } }, '/favicon.ico': { headers: { 'Cache-Control': 'public, max-age=86400' } }, // 图片、CSS、JS等静态资源缓存 '/**/*.{png,jpg,jpeg,gif,webp,svg,ico}': { headers: { 'Cache-Control': 'public, max-age=31536000, immutable' } }, '/**/*.{css,js}': { headers: { 'Cache-Control': 'public, max-age=31536000, immutable' } }, // 认证相关页面不缓存 '/login': { headers: { 'Cache-Control': 'no-cache, no-store, must-revalidate', Pragma: 'no-cache', Expires: '0' } }, '/dashboard': { headers: { 'Cache-Control': 'no-cache, no-store, must-revalidate', Pragma: 'no-cache', Expires: '0' } }, '/change-password': { headers: { 'Cache-Control': 'no-cache, no-store, must-revalidate', Pragma: 'no-cache', Expires: '0' } }, '/auth/**': { headers: { 'Cache-Control': 'no-cache, no-store, must-revalidate', Pragma: 'no-cache', Expires: '0' } }, '/notification-settings': { headers: { 'Cache-Control': 'no-cache, no-store, must-revalidate', Pragma: 'no-cache', Expires: '0' } } }, // 根据部署环境调整配置 ...(process.env.VERCEL ? { // Vercel 环境:使用标准配置 } : process.env.NETLIFY ? { // Netlify 环境:确保 Drizzle 正确打包 experimental: { wasm: true } } : { // 其他环境:使用标准配置 }) }, // Vite 配置 vite: { resolve: { alias: [ { find: '@applemusic-like-lyrics/core/style.css', replacement: fileURLToPath( new URL('./vendor/amll-core/src/styles/index.css', import.meta.url) ) }, { find: '@applemusic-like-lyrics/core', replacement: fileURLToPath(new URL('./vendor/amll-core/src/index.ts', import.meta.url)) } ] }, plugins: [wasm(), topLevelAwait(), glsl()], optimizeDeps: { include: ['drizzle-orm'], exclude: ['@applemusic-like-lyrics/vue', '@applemusic-like-lyrics/lyric'] }, build: { sourcemap: false, rollupOptions: { output: { manualChunks(id) { if (!id.includes('node_modules')) return if (id.includes('lucide-vue-next')) return 'icons' if (id.includes('@pixi')) return 'pixi' if (id.includes('@applemusic-like-lyrics')) return 'lyric-engine' if (id.includes('drizzle-orm') || id.includes('postgres')) return 'database' if (id.includes('xlsx') || id.includes('jspdf') || id.includes('jszip')) return 'office' } } } }, // 添加 WASM 支持配置 assetsInclude: ['**/*.wasm'], // SSR配置 ssr: { noExternal: process.env.NETLIFY ? ['drizzle-orm', 'postgres'] : process.env.VERCEL ? [] : ['drizzle-orm', 'postgres'] } } })