#!/usr/bin/env node /** * Electron Development Script * * This script provides hot-reload development mode for Electron applications. * It automatically builds Electron dependencies, starts the Remix development server, * and launches the Electron application with hot-reload capabilities. */ import { spawn, exec } from 'node:child_process'; import path from 'node:path'; import fs from 'node:fs'; import { fileURLToPath } from 'node:url'; // Get current file directory const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); // Constants const REMIX_PORT = 5173; const CHECK_INTERVAL = 1000; const MAX_RETRIES = 30; // Set environment variables process.env.NODE_ENV = 'development'; console.log('šŸš€ Starting Electron hot-reload development mode...'); console.log('šŸ”§ Environment:', process.env.NODE_ENV); let electronProcess = null; let remixProcess = null; /** * Cleanup function to gracefully shutdown all processes */ function cleanup() { console.log('\nšŸ›‘ Shutting down all processes...'); if (electronProcess) { electronProcess.kill('SIGTERM'); } if (remixProcess) { remixProcess.kill('SIGTERM'); } process.exit(0); } // Handle process exit signals process.on('SIGINT', cleanup); process.on('SIGTERM', cleanup); /** * Wait for a server to start on the specified port * @param {number} port - Port number to check * @param {string} serverName - Name of the server for logging * @returns {Promise} */ async function waitForServer(port, serverName) { return new Promise((resolve, reject) => { let retries = 0; const checkServer = () => { exec(`lsof -i :${port}`, (error, stdout) => { if (stdout) { console.log(`āœ… ${serverName} started`); resolve(); } else if (retries >= MAX_RETRIES) { reject(new Error(`Timeout waiting for ${serverName} to start`)); } else { retries++; setTimeout(checkServer, CHECK_INTERVAL); } }); }; checkServer(); }); } /** * Build Electron dependencies * @returns {Promise} */ async function buildElectronDeps() { return new Promise((resolve, reject) => { const buildProcess = spawn('pnpm', ['electron:build:deps'], { stdio: 'inherit', env: { ...process.env }, }); buildProcess.on('close', (code) => { if (code === 0) { console.log('āœ… Electron dependencies built successfully'); resolve(); } else { reject(new Error(`Build failed with exit code: ${code}`)); } }); buildProcess.on('error', (error) => { reject(new Error(`Build process error: ${error.message}`)); }); }); } /** * Main function to start Electron development mode * @returns {Promise} */ async function startElectronDev() { try { // 1. Build Electron dependencies first console.log('šŸ“¦ Building Electron dependencies...'); await buildElectronDeps(); // 2. Start Remix development server console.log('🌐 Starting Remix development server...'); remixProcess = spawn('pnpm', ['dev'], { stdio: 'pipe', env: { ...process.env }, }); remixProcess.stdout.on('data', (data) => { const output = data.toString(); console.log(`[Remix] ${output.trim()}`); }); remixProcess.stderr.on('data', (data) => { console.error(`[Remix Error] ${data.toString().trim()}`); }); // Wait for Remix server to start await waitForServer(REMIX_PORT, 'Remix development server'); // 3. Start Electron application console.log('⚔ Starting Electron application...'); const electronPath = path.join(__dirname, '..', 'node_modules', '.bin', 'electron'); const mainPath = path.join(__dirname, '..', 'build', 'electron', 'main', 'index.mjs'); // Check if main process file exists if (!fs.existsSync(mainPath)) { throw new Error(`Main process file not found: ${mainPath}`); } electronProcess = spawn(electronPath, [mainPath], { stdio: 'inherit', env: { ...process.env, NODE_ENV: 'development', ELECTRON_IS_DEV: '1', }, }); electronProcess.on('error', (error) => { console.error('āŒ Failed to start Electron:', error); cleanup(); }); electronProcess.on('exit', (code) => { console.log(`šŸ“± Electron process exited with code: ${code}`); if (code !== 0) { cleanup(); } }); console.log('šŸŽ‰ Electron hot-reload development mode started!'); console.log('šŸ’” Code changes will automatically reload'); console.log('šŸ›‘ Press Ctrl+C to exit'); } catch (error) { console.error('āŒ Startup failed:', error.message); cleanup(); } } // Start development mode startElectronDev();