const { spawn } = require('child_process'); const { createServer, build } = require('vite'); const electron = require('electron'); const path = require('path'); const fs = require('fs'); /** * @type {import('vite').LogLevel} */ const LOG_LEVEL = 'info'; /** @type {import('vite').InlineConfig} */ const sharedConfig = { mode: 'development', build: { watch: {}, }, logLevel: LOG_LEVEL, }; /** @type {import('vite').InlineConfig} */ const preloadConfig = { ...sharedConfig, configFile: false, root: path.join(__dirname, '..'), build: { ...sharedConfig.build, outDir: 'dist-electron', lib: { entry: path.join(__dirname, '../electron/preload.ts'), formats: ['cjs'], }, rollupOptions: { external: ['electron'], output: { entryFileNames: '[name].js', }, }, emptyOutDir: true, }, }; // Find all TypeScript files in the electron directory const electronDir = path.join(__dirname, '../electron'); const entries = {}; function addEntry(file) { const relativePath = path.relative(electronDir, file); const name = relativePath.replace(/\.ts$/, ''); entries[name] = file; } function scanDirectory(dir) { const files = fs.readdirSync(dir); files.forEach(file => { const fullPath = path.join(dir, file); const stat = fs.statSync(fullPath); if (stat.isDirectory()) { scanDirectory(fullPath); } else if (file.endsWith('.ts')) { addEntry(fullPath); } }); } scanDirectory(electronDir); /** @type {import('vite').InlineConfig} */ const mainConfig = { ...sharedConfig, configFile: false, root: path.join(__dirname, '..'), build: { ...sharedConfig.build, outDir: 'dist-electron', lib: { entry: entries, formats: ['cjs'], }, rollupOptions: { external: ['electron', 'electron-store', 'path', 'os', 'chokidar', 'openai', 'openrouter-client', 'ollama'], output: { entryFileNames: '[name].js', format: 'cjs', preserveModules: true, preserveModulesRoot: path.join(__dirname, '../electron'), }, }, emptyOutDir: false, }, }; /** * @type {(server: import('vite').ViteDevServer) => Promise} */ function watchMain(server) { /** * @type {import('child_process').ChildProcessWithoutNullStreams | null} */ let electronProcess = null; return build({ ...mainConfig, plugins: [{ name: 'electron-main-watcher', writeBundle() { if (electronProcess) { electronProcess.kill(); electronProcess = null; } electronProcess = spawn(electron, ['.'], { stdio: 'inherit', env: { ...process.env, VITE_DEV_SERVER_URL: `http://localhost:${server.config.server.port}`, }, }); }, }], }); } /** * @type {() => Promise} */ function watchPreload() { return build(preloadConfig); } // bootstrap async function start() { try { console.log('Starting Vite dev server...'); const server = await createServer({ ...sharedConfig }); await server.listen(); console.log(`Dev server running at: ${server.config.server.port}`); console.log('Building preload script...'); await watchPreload(); console.log('Starting Electron...'); await watchMain(server); console.log('Development environment ready!'); } catch (error) { console.error('Error starting dev server:', error); process.exit(1); } } start();