const { app, BrowserWindow } = require('electron') const path = require('path') const http = require('http') const os = require('os') const fs = require('fs') const config = require('../configs/config.js') const isDev = process.env.NODE_ENV === 'development' || !app.isPackaged // 修复缓存权限问题:设置用户数据目录到有权限的位置 // 必须在 app.whenReady() 之前调用 if (process.platform === 'win32') { try { // 设置缓存目录到用户临时目录,避免权限问题 const userDataPath = path.join(os.tmpdir(), 'electron-react-vite-app') // 确保目录存在 if (!fs.existsSync(userDataPath)) { fs.mkdirSync(userDataPath, { recursive: true }) } // 创建缓存子目录 const cacheDir = path.join(userDataPath, 'cache') const gpuCacheDir = path.join(userDataPath, 'gpu-cache') if (!fs.existsSync(cacheDir)) { fs.mkdirSync(cacheDir, { recursive: true }) } if (!fs.existsSync(gpuCacheDir)) { fs.mkdirSync(gpuCacheDir, { recursive: true }) } // 设置用户数据路径(必须在 app.whenReady() 之前) app.setPath('userData', userDataPath) // 设置缓存目录到有权限的位置 app.commandLine.appendSwitch('disk-cache-dir', cacheDir) app.commandLine.appendSwitch('gpu-disk-cache-dir', gpuCacheDir) console.log(`[OK] Cache directories set to: ${userDataPath}`) } catch (error) { console.warn('[WARN] Failed to set cache directories:', error.message) // 如果设置失败,尝试禁用 GPU 缓存作为备选方案 app.commandLine.appendSwitch('disable-gpu-sandbox') } } /** * 检测 Vite 开发服务器实际使用的端口 * 如果配置的端口被占用,Vite 会自动尝试下一个端口 * 需要确认是 Vite 服务器,而不仅仅是端口响应 */ async function findVitePort(startPort, maxAttempts = 10) { const viteHost = config.vite?.host || 'localhost' for (let offset = 0; offset < maxAttempts; offset++) { const port = startPort + offset const isViteServer = await new Promise((resolve) => { const req = http.get(`http://${viteHost}:${port}`, (res) => { // 检查状态码 if (res.statusCode !== 200) { resolve(false) return } // 读取响应数据确认是否是 Vite 服务器 let data = '' let resolved = false res.on('data', (chunk) => { if (resolved) return data += chunk.toString() // 如果响应包含 Vite 特征,立即确认 if (data.length > 100 && (data.includes('/vite') || data.includes('Vite') || data.includes('vite/client'))) { resolved = true resolve(true) } }) res.on('end', () => { if (resolved) return // 检查响应内容是否包含 Vite 特征 if (data.includes('/vite') || data.includes('Vite') || data.includes('vite/client')) { resolve(true) } else { resolve(false) } }) }) req.on('error', () => { resolve(false) }) req.setTimeout(2000, () => { req.destroy() resolve(false) }) }) if (isViteServer) { return port } } // 如果找不到,返回配置的端口 return startPort } async function createWindow() { const mainWindow = new BrowserWindow({ width: config.window.width, height: config.window.height, autoHideMenuBar: config.window.autoHideMenuBar, // 从配置文件读取 webPreferences: { nodeIntegration: false, contextIsolation: true } }) if (isDev) { // 从配置文件读取 Vite 开发服务器端口 const configPort = config.vite?.port || 5173 // 检测实际使用的端口(如果配置端口被占用,Vite 会自动尝试下一个) const vitePort = await findVitePort(configPort) const viteHost = config.vite?.host || 'localhost' console.log(`Loading Vite dev server at http://${viteHost}:${vitePort}`) mainWindow.loadURL(`http://${viteHost}:${vitePort}`) // 根据配置文件决定是否打开调试侧边栏 if (config.devTools.enabled) { mainWindow.webContents.openDevTools() } } else { mainWindow.loadFile(path.join(__dirname, '../dist/index.html')) } } app.whenReady().then(() => { createWindow() app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) { createWindow() } }) }) app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit() } })