#!/usr/bin/env node import { spawn, spawnSync } from 'node:child_process'; import { existsSync, readFileSync } from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; const scriptDir = path.dirname(fileURLToPath(import.meta.url)); const projectRoot = path.resolve(scriptDir, '..'); const frontendDir = path.join(projectRoot, 'frontend'); const wailsConfigPath = path.join(projectRoot, 'wails.json'); const nodeCommand = process.execPath; const wailsCommand = process.platform === 'win32' ? 'wails.exe' : 'wails'; const usage = `Usage: node tools/wails-fast-dev.mjs [--refresh-bindings] [--no-install] [--dry-run] [wails dev flags...] Fast path: - skips npm install when frontend dependencies are unchanged - runs wails dev with -m -s -nosyncgomod -skipembedcreate - skips Wails binding generation unless --refresh-bindings is passed Use --refresh-bindings after changing exported Go method signatures.`; const rawArgs = process.argv.slice(2); if (rawArgs.includes('--help') || rawArgs.includes('-h')) { console.log(usage); process.exit(0); } const readWailsConfig = () => { try { return JSON.parse(readFileSync(wailsConfigPath, 'utf8')); } catch (error) { console.error(`Failed to read wails.json: ${error.message}`); process.exit(1); } }; const runFrontendInstall = () => { const result = spawnSync(nodeCommand, ['scripts/wails-frontend-install.mjs'], { cwd: frontendDir, env: process.env, stdio: 'inherit', }); if (result.status !== 0) { process.exit(result.status ?? 1); } }; const hasFlag = (args, names) => args.some((arg) => names.some((name) => arg === name || arg.startsWith(`${name}=`))); const wailsConfig = readWailsConfig(); const dryRun = rawArgs.includes('--dry-run'); const refreshBindings = rawArgs.includes('--refresh-bindings') || process.env.GONAVI_REFRESH_WAILS_BINDINGS === '1'; const skipInstall = rawArgs.includes('--no-install') || process.env.GONAVI_FAST_DEV_SKIP_INSTALL === '1'; const passThroughArgs = rawArgs.filter((arg) => arg !== '--refresh-bindings' && arg !== '--no-install' && arg !== '--dry-run'); const devServerUrl = process.env.GONAVI_FRONTEND_DEV_SERVER_URL || wailsConfig['frontend:dev:serverUrl'] || 'http://localhost:5173'; const wailsjsRoot = path.resolve(projectRoot, wailsConfig.wailsjsdir || './frontend', 'wailsjs'); const skipBindings = !refreshBindings && existsSync(wailsjsRoot); const fastArgs = ['dev']; if (!skipInstall && !dryRun) { runFrontendInstall(); } if (!hasFlag(passThroughArgs, ['-m'])) { fastArgs.push('-m'); } if (!hasFlag(passThroughArgs, ['-s'])) { fastArgs.push('-s'); } if (!hasFlag(passThroughArgs, ['-nosyncgomod'])) { fastArgs.push('-nosyncgomod'); } if (!hasFlag(passThroughArgs, ['-skipembedcreate'])) { fastArgs.push('-skipembedcreate'); } if (skipBindings && !hasFlag(passThroughArgs, ['-skipbindings'])) { fastArgs.push('-skipbindings'); } if (!hasFlag(passThroughArgs, ['-frontenddevserverurl'])) { fastArgs.push('-frontenddevserverurl', devServerUrl); } if (!skipBindings && !refreshBindings) { console.warn('frontend/wailsjs not found; generating Wails bindings this run.'); } if (dryRun) { const quoteArg = (arg) => (/\s/.test(arg) ? JSON.stringify(arg) : arg); console.log(`Would run: ${[wailsCommand, ...fastArgs, ...passThroughArgs].map(quoteArg).join(' ')}`); process.exit(0); } const child = spawn(wailsCommand, [...fastArgs, ...passThroughArgs], { cwd: projectRoot, env: process.env, stdio: 'inherit', }); child.on('exit', (code, signal) => { if (signal) { process.kill(process.pid, signal); return; } process.exit(code ?? 0); }); child.on('error', (error) => { console.error(`Failed to start Wails CLI: ${error.message}`); process.exit(1); });