feat: enhance Electron build process and server preparation

- Added new build scripts for Electron targeting Windows, macOS, and Linux.
- Updated the main build script to include server preparation steps.
- Introduced a new script to prepare the server for bundling with Electron, including cleaning previous builds and installing production dependencies.
- Modified the Electron main process to verify server file existence and improved error handling.
- Updated .gitignore to exclude the new server-bundle directory.
This commit is contained in:
SuperComboGamer
2025-12-13 16:40:09 -05:00
parent e2c238f4f8
commit bc46a18372
5 changed files with 105 additions and 7 deletions

1
apps/app/.gitignore vendored
View File

@@ -48,3 +48,4 @@ next-env.d.ts
# Electron
/dist/
/server-bundle/

View File

@@ -63,18 +63,31 @@ async function startServer() {
command = "node";
serverPath = path.join(process.resourcesPath, "server", "index.js");
args = [serverPath];
// Verify server files exist
if (!fs.existsSync(serverPath)) {
throw new Error(`Server not found at: ${serverPath}`);
}
}
// Set environment variables for server
const serverNodeModules = app.isPackaged
? path.join(process.resourcesPath, "server", "node_modules")
: path.join(__dirname, "../../server/node_modules");
const env = {
...process.env,
PORT: SERVER_PORT.toString(),
DATA_DIR: app.getPath("userData"),
NODE_PATH: serverNodeModules,
};
console.log("[Electron] Starting backend server...");
console.log("[Electron] Server path:", serverPath);
console.log("[Electron] NODE_PATH:", serverNodeModules);
serverProcess = spawn(command, args, {
cwd: path.dirname(serverPath),
env,
stdio: ["ignore", "pipe", "pipe"],
});
@@ -92,6 +105,11 @@ async function startServer() {
serverProcess = null;
});
serverProcess.on("error", (err) => {
console.error(`[Server] Failed to start server process:`, err);
serverProcess = null;
});
// Wait for server to be ready
await waitForServer();
}

View File

@@ -20,7 +20,10 @@
"dev:electron": "concurrently \"next dev -p 3007\" \"wait-on http://localhost:3007 && electron .\"",
"dev:electron:debug": "concurrently \"next dev -p 3007\" \"wait-on http://localhost:3007 && OPEN_DEVTOOLS=true electron .\"",
"build": "next build",
"build:electron": "next build && electron-builder",
"build:electron": "node scripts/prepare-server.js && next build && electron-builder",
"build:electron:win": "node scripts/prepare-server.js && next build && electron-builder --win",
"build:electron:mac": "node scripts/prepare-server.js && next build && electron-builder --mac",
"build:electron:linux": "node scripts/prepare-server.js && next build && electron-builder --linux",
"start": "next start",
"lint": "eslint",
"test": "playwright test",
@@ -79,13 +82,13 @@
"@types/react": "^19",
"@types/react-dom": "^19",
"concurrently": "^9.2.1",
"electron": "^39.2.6",
"electron": "39.2.7",
"electron-builder": "^26.0.12",
"eslint": "^9",
"eslint-config-next": "16.0.7",
"tailwindcss": "^4",
"tw-animate-css": "^1.4.0",
"typescript": "^5",
"typescript": "5.9.3",
"wait-on": "^9.0.3"
},
"build": {
@@ -103,11 +106,17 @@
],
"extraResources": [
{
"from": ".env",
"from": "server-bundle/dist",
"to": "server"
},
{
"from": "server-bundle/node_modules",
"to": "server/node_modules"
},
{
"from": "../../.env",
"to": ".env",
"filter": [
"**/*"
]
"filter": ["**/*"]
}
],
"mac": {

View File

@@ -0,0 +1,67 @@
#!/usr/bin/env node
/**
* This script prepares the server for bundling with Electron.
* It copies the server dist and installs production dependencies
* in a way that works with npm workspaces.
*/
import { execSync } from 'child_process';
import { cpSync, existsSync, mkdirSync, rmSync, writeFileSync, readFileSync } from 'fs';
import { join, dirname } from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const APP_DIR = join(__dirname, '..');
const SERVER_DIR = join(APP_DIR, '..', 'server');
const BUNDLE_DIR = join(APP_DIR, 'server-bundle');
console.log('🔧 Preparing server for Electron bundling...\n');
// Step 1: Clean up previous bundle
if (existsSync(BUNDLE_DIR)) {
console.log('🗑️ Cleaning previous server-bundle...');
rmSync(BUNDLE_DIR, { recursive: true });
}
mkdirSync(BUNDLE_DIR, { recursive: true });
// Step 2: Build the server TypeScript
console.log('📦 Building server TypeScript...');
execSync('npm run build', { cwd: SERVER_DIR, stdio: 'inherit' });
// Step 3: Copy server dist
console.log('📋 Copying server dist...');
cpSync(join(SERVER_DIR, 'dist'), join(BUNDLE_DIR, 'dist'), { recursive: true });
// Step 4: Create a minimal package.json for the server
console.log('📝 Creating server package.json...');
const serverPkg = JSON.parse(readFileSync(join(SERVER_DIR, 'package.json'), 'utf-8'));
const bundlePkg = {
name: '@automaker/server-bundle',
version: serverPkg.version,
type: 'module',
main: 'dist/index.js',
dependencies: serverPkg.dependencies
};
writeFileSync(
join(BUNDLE_DIR, 'package.json'),
JSON.stringify(bundlePkg, null, 2)
);
// Step 5: Install production dependencies
console.log('📥 Installing server production dependencies...');
execSync('npm install --omit=dev', {
cwd: BUNDLE_DIR,
stdio: 'inherit',
env: {
...process.env,
// Prevent npm from using workspace resolution
npm_config_workspace: ''
}
});
console.log('\n✅ Server prepared for bundling at:', BUNDLE_DIR);

View File

@@ -18,6 +18,9 @@
"build": "npm run build --workspace=apps/app",
"build:server": "npm run build --workspace=apps/server",
"build:electron": "npm run build:electron --workspace=apps/app",
"build:electron:win": "npm run build:electron:win --workspace=apps/app",
"build:electron:mac": "npm run build:electron:mac --workspace=apps/app",
"build:electron:linux": "npm run build:electron:linux --workspace=apps/app",
"start": "npm run start --workspace=apps/app",
"start:server": "npm run start --workspace=apps/server",
"lint": "npm run lint --workspace=apps/app",