Files
OpenNoodl/scripts/start.ts
2026-01-08 13:27:38 +01:00

165 lines
4.3 KiB
TypeScript
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { exec, ChildProcess, execSync } from 'child_process';
import fs from 'fs';
import path from 'path';
import { ConsoleColor, attachStdio } from './utils/process';
// Track all spawned processes for cleanup
const childProcesses: ChildProcess[] = [];
/**
* Kills a process and all its children (the entire process tree).
* This is crucial for webpack/node processes that spawn child processes.
*/
function killProcessTree(proc: ChildProcess): void {
if (!proc.pid) return;
try {
if (process.platform === 'win32') {
// Windows: use taskkill with /T flag to kill tree
execSync(`taskkill /pid ${proc.pid} /T /F`, { stdio: 'ignore' });
} else {
// macOS/Linux: kill the entire process group
// Try to kill the process group (negative PID)
try {
process.kill(-proc.pid, 'SIGTERM');
} catch {
// If process group kill fails, try direct kill
proc.kill('SIGTERM');
}
}
} catch (error) {
// Process might already be dead - that's okay
}
}
/**
* Cleanup function that kills all child processes
*/
function cleanup(): void {
console.log('\n🧹 Cleaning up child processes...');
for (const proc of childProcesses) {
killProcessTree(proc);
}
// Also kill any lingering webpack processes from this session
try {
if (process.platform !== 'win32') {
// Kill any webpack processes that might be orphaned
execSync('pkill -f "webpack.*noodl" 2>/dev/null || true', { stdio: 'ignore' });
}
} catch {
// Ignore errors - processes might not exist
}
console.log('✅ Cleanup complete');
}
const CWD = path.join(__dirname, '..');
const LOCAL_GIT_DIRECTORY = path.join(__dirname, '..', 'node_modules', 'dugite', 'git');
const LOCAL_GIT_TRAMPOLINE_DIRECTORY = path.join(
__dirname,
'..',
'node_modules',
'desktop-trampoline/build/Release/desktop-trampoline'
);
// Print variables for easy debugging
console.log('---');
console.log(`> CWD: `, CWD);
console.log(`> LOCAL_GIT_DIRECTORY: `, LOCAL_GIT_DIRECTORY);
console.log(`> LOCAL_GIT_TRAMPOLINE_DIRECTORY: `, LOCAL_GIT_TRAMPOLINE_DIRECTORY);
console.log('---');
// Verify git path
switch (process.platform) {
case 'win32': {
const gitExist = fs.existsSync(path.join(LOCAL_GIT_DIRECTORY, 'mingw64/bin', 'git.exe'));
if (gitExist) {
console.log('> Found git.exe');
} else {
throw new Error("'git.exe' is missing, this can be caused by node_modules issues.");
}
break;
}
case 'darwin': {
const gitExist = fs.existsSync(path.join(LOCAL_GIT_DIRECTORY, 'bin', 'git'));
if (gitExist) {
console.log('> Found git executable');
} else {
throw new Error("'git' is missing, this can be caused by node_modules issues.");
}
break;
}
}
console.log('---');
// Start processes
const processOptions = {
cwd: CWD,
env: {
...process.env,
LOCAL_GIT_DIRECTORY,
LOCAL_GIT_TRAMPOLINE_DIRECTORY
}
};
const argBuildViewers = process.argv.includes('--build-viewer');
const viewerScript = argBuildViewers ? 'build' : 'start';
const viewerProcess = attachStdio(
exec(`npx lerna exec --scope @noodl/noodl-viewer-react -- npm run ${viewerScript}`, processOptions),
{
prefix: 'Viewer',
color: ConsoleColor.FgMagenta
}
);
childProcesses.push(viewerProcess);
const cloudRuntimeProcess = attachStdio(
exec(`npx lerna exec --scope @noodl/cloud-runtime -- npm run ${viewerScript}`, processOptions),
{
prefix: 'Cloud',
color: ConsoleColor.FgMagenta
}
);
childProcesses.push(cloudRuntimeProcess);
const editorProcess = attachStdio(exec('npx lerna exec --scope noodl-editor -- npm run start', processOptions), {
prefix: 'Editor',
color: ConsoleColor.FgCyan
});
childProcesses.push(editorProcess);
// Handle editor exit - cleanup and exit
editorProcess.on('exit', (code) => {
if (typeof code === 'number') {
cleanup();
process.exit(0);
}
});
// Handle Ctrl+C (SIGINT) - cleanup all processes
process.on('SIGINT', () => {
console.log('\n\n⚠ Received SIGINT (Ctrl+C)');
cleanup();
process.exit(0);
});
// Handle SIGTERM - cleanup all processes
process.on('SIGTERM', () => {
console.log('\n\n⚠ Received SIGTERM');
cleanup();
process.exit(0);
});
// Handle uncaught exceptions - still try to cleanup
process.on('uncaughtException', (err) => {
console.error('\n\n❌ Uncaught exception:', err);
cleanup();
process.exit(1);
});