Files
Twitch-VOD-Manager/scripts/dev.mjs
T
Sucukdeluxe c66e9c9ab1 Fix remaining UI state and shutdown edge cases
Keep the loaded cutter layout stable across supported window sizes, preserve recovered encoder choices during capability discovery, and reject unsupported video selections without changing the active project.

Honor the Windows system theme, fully localize runtime metrics, invalidate imported System Check state safely, and bound child-process shutdown waits when close events never arrive.

Extend focused and Electron smoke coverage and prepare the v1.0.17 public release metadata.
2026-08-13 11:24:48 +02:00

117 lines
4.0 KiB
JavaScript

import { spawn } from 'node:child_process';
import { fileURLToPath } from 'node:url';
import { pathToFileURL } from 'node:url';
import { watch } from 'node:fs';
import { dirname, resolve } from 'node:path';
const scriptPath = fileURLToPath(import.meta.url);
const rootDirectory = resolve(dirname(scriptPath), '..');
const typescriptCli = resolve(rootDirectory, 'node_modules', 'typescript', 'bin', 'tsc');
const electronSourceExecutable = process.platform === 'win32'
? resolve(rootDirectory, 'node_modules', 'electron', 'dist', 'electron.exe')
: resolve(rootDirectory, 'node_modules', '.bin', 'electron');
let electronExecutable = electronSourceExecutable;
const outputDirectory = resolve(rootDirectory, 'dist');
const developmentProgramData = resolve(rootDirectory, '.dev-program-data');
const developmentUserData = resolve(rootDirectory, '.dev-user-data');
const developmentRelaunchCommand = `"${process.execPath}" "${scriptPath}" --once`;
const runOnce = process.argv.includes('--once');
let electronProcess;
let restarting = false;
let restartTimer;
let compiler;
let outputWatcher;
function run(command, args, options = {}) {
return spawn(command, args, { cwd: rootDirectory, stdio: 'inherit', ...options });
}
function waitForExit(child) {
return new Promise((resolveExit, reject) => {
child.once('error', reject);
child.once('exit', (code) => resolveExit(code ?? 1));
});
}
function startElectron() {
electronProcess = run(electronExecutable, [`--user-data-dir=${developmentUserData}`, '.'], {
env: {
...process.env,
PROGRAMDATA: developmentProgramData,
TWITCH_VOD_MANAGER_DEV: '1',
TWITCH_VOD_MANAGER_RELAUNCH_COMMAND: developmentRelaunchCommand,
},
});
electronProcess.once('exit', () => {
electronProcess = undefined;
});
return electronProcess;
}
function restartElectron() {
if (restarting) return;
restarting = true;
if (electronProcess) {
electronProcess.once('exit', () => {
restarting = false;
startElectron();
});
electronProcess.kill();
return;
}
restarting = false;
startElectron();
}
function isElectronRestartTarget(fileName) {
const baseName = fileName.replaceAll('\\', '/').split('/').at(-1) ?? '';
if (baseName === 'renderer.js') return false;
if (!baseName.startsWith('renderer') || !baseName.endsWith('.js')) return true;
const suffix = baseName.slice(8);
return suffix.length <= 4 || (suffix[0] !== '-' && suffix[0] !== '.');
}
function scheduleRestart(fileName) {
if (!fileName || !isElectronRestartTarget(fileName.toString())) return;
clearTimeout(restartTimer);
restartTimer = setTimeout(restartElectron, 200);
}
function stop(child) {
if (child && !child.killed) child.kill();
}
const initialCompile = run(process.execPath, [typescriptCli]);
const initialExitCode = await waitForExit(initialCompile);
if (initialExitCode !== 0) process.exit(initialExitCode);
if (process.platform === 'win32') {
const helperPath = pathToFileURL(resolve(outputDirectory, 'main', 'dev-executable.js')).href;
const { prepareWindowsDevExecutable } = await import(helperPath);
electronExecutable = await prepareWindowsDevExecutable({
sourcePath: electronSourceExecutable,
destinationPath: resolve(rootDirectory, 'node_modules', 'electron', 'dist', 'Twitch VOD Manager.exe'),
iconPath: resolve(rootDirectory, 'build', 'icon.ico'),
version: '1.0.17',
});
}
for (const signal of ['SIGINT', 'SIGTERM']) {
process.once(signal, () => {
outputWatcher?.close();
clearTimeout(restartTimer);
stop(compiler);
stop(electronProcess);
process.exit();
});
}
if (runOnce) {
process.exitCode = await waitForExit(startElectron());
} else {
compiler = run(process.execPath, [typescriptCli, '--watch', '--preserveWatchOutput']);
outputWatcher = watch(outputDirectory, { recursive: true }, (_, fileName) => scheduleRestart(fileName));
startElectron();
}