Files
pwa/scripts/prepare-dev.mjs
ar.badieiandCursor 370ac15471 Ship Novya PWA with backend for deployable production use.
Fix production TypeScript builds and add DEPLOY.md so the app can be hosted from this repo.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-03 21:01:52 +03:30

101 lines
2.7 KiB
JavaScript

/**
* Prepare local dev: free backend port and ensure MySQL is reachable.
* Runs automatically via npm "predev" before `npm run dev`.
*/
import { execSync } from 'node:child_process';
import net from 'node:net';
import { platform } from 'node:os';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
const MYSQL_PORT = 3306;
const BACKEND_LISTEN_PORT = 3001;
const FRONTEND_PORT = 5173;
const __dirname = dirname(fileURLToPath(import.meta.url));
const rootDir = join(__dirname, '..');
const backendDir = join(rootDir, 'backend');
function log(msg) {
console.log(`[prepare-dev] ${msg}`);
}
function isPortOpen(port, host = '127.0.0.1') {
return new Promise((resolve) => {
const socket = net.createConnection({ port, host }, () => {
socket.destroy();
resolve(true);
});
socket.on('error', () => resolve(false));
socket.setTimeout(1500, () => {
socket.destroy();
resolve(false);
});
});
}
function freePort(port) {
if (platform() === 'win32') {
try {
const out = execSync(`netstat -ano | findstr :${port}`, { encoding: 'utf8' });
const pids = new Set();
for (const line of out.split('\n')) {
if (!line.includes('LISTENING')) continue;
const parts = line.trim().split(/\s+/);
const pid = parts[parts.length - 1];
if (pid && pid !== '0') pids.add(pid);
}
for (const pid of pids) {
log(`Stopping process ${pid} on port ${port}`);
execSync(`taskkill /F /PID ${pid}`, { stdio: 'ignore' });
}
} catch {
// nothing listening
}
return;
}
try {
execSync(`lsof -ti:${port} | xargs kill -9 2>/dev/null`, { stdio: 'ignore', shell: true });
} catch {
// nothing listening
}
}
async function ensureMysql() {
if (await isPortOpen(MYSQL_PORT)) {
log(`MySQL is reachable on port ${MYSQL_PORT}`);
return;
}
log(`MySQL not reachable on port ${MYSQL_PORT}; starting Docker Compose...`);
try {
execSync('docker compose -f docker-compose.dev.yml up -d', {
cwd: backendDir,
stdio: 'inherit',
});
} catch {
console.error(
'[prepare-dev] ERROR: MySQL is not running. Start it with:\n' +
' cd backend && docker compose -f docker-compose.dev.yml up -d',
);
process.exit(1);
}
for (let i = 0; i < 30; i += 1) {
if (await isPortOpen(MYSQL_PORT)) {
log('MySQL is ready');
return;
}
await new Promise((r) => setTimeout(r, 1000));
}
console.error('[prepare-dev] ERROR: MySQL did not become ready in time.');
process.exit(1);
}
freePort(BACKEND_LISTEN_PORT);
freePort(FRONTEND_PORT);
await ensureMysql();
log(`Ready — backend will listen on port ${BACKEND_LISTEN_PORT}`);