refactor(launcher): move detached app spawning into runtime utilities

This commit is contained in:
2026-08-11 18:51:24 -07:00
parent 91c6ea492f
commit 4a76956257
3 changed files with 32 additions and 18 deletions
+13
View File
@@ -25,8 +25,21 @@ import {
applyBackgroundBootstrapCommandLineSwitches,
applyEarlyLinuxCommandLineSwitches,
resolveLinuxPasswordStoreValue,
spawnDetachedApp,
} from './main-entry-runtime';
test('detached app launch policy stays in the startup runtime utilities', () => {
const entrySource = fs.readFileSync(path.join(process.cwd(), 'src/main-entry.ts'), 'utf8');
const runtimeSource = fs.readFileSync(
path.join(process.cwd(), 'src/main-entry-runtime.ts'),
'utf8',
);
assert.equal(typeof spawnDetachedApp, 'function');
assert.doesNotMatch(entrySource, /function spawnDetachedApp/);
assert.match(runtimeSource, /child\.unref\(\)/);
});
test('background bootstrap exits through Electron so Chromium children shut down', () => {
const exitCodes: number[] = [];
exitBackgroundBootstrap({ exit: (code) => exitCodes.push(code) });
+18
View File
@@ -1,7 +1,9 @@
import fs from 'node:fs';
import os from 'node:os';
import { spawn } from 'node:child_process';
import { CliArgs, hasExplicitCommand, parseArgs, shouldStartApp } from './cli/args';
import { resolveConfigDir } from './config/path-resolution';
import { resolveAppImageMountKeepaliveInvocation } from './main/appimage-mount-keepalive';
const BACKGROUND_ARG = '--background';
const START_ARG = '--start';
@@ -265,6 +267,22 @@ export function exitBackgroundBootstrap(app: BackgroundBootstrapAppLike): void {
app.exit(0);
}
export function spawnDetachedApp(childArgs: string[], env: NodeJS.ProcessEnv): void {
const keepalive = resolveAppImageMountKeepaliveInvocation(env);
const child = keepalive
? spawn(keepalive.command, [...keepalive.args, ...childArgs], {
detached: true,
stdio: 'ignore',
env,
})
: spawn(process.execPath, childArgs, {
detached: true,
stdio: 'ignore',
env,
});
child.unref();
}
export function shouldHandleHelpOnlyAtEntry(argv: string[], env: NodeJS.ProcessEnv): boolean {
if (env.ELECTRON_RUN_AS_NODE === '1') return false;
const args = parseCliArgs(argv);
+1 -18
View File
@@ -1,5 +1,4 @@
import os from 'node:os';
import { spawn } from 'node:child_process';
import { app, dialog, shell } from 'electron';
import { printHelp } from './cli/help';
import {
@@ -20,9 +19,9 @@ import {
shouldHandleHelpOnlyAtEntry,
shouldHandleLaunchMpvAtEntry,
shouldHandleStatsDaemonCommandAtEntry,
spawnDetachedApp,
} from './main-entry-runtime';
import { requestSingleInstanceLockEarly } from './main/early-single-instance';
import { resolveAppImageMountKeepaliveInvocation } from './main/appimage-mount-keepalive';
import { readConfiguredWindowsMpvLaunch } from './main-entry-launch-config';
import { isAppControlServerAvailable, sendAppControlCommand } from './shared/app-control-client';
import {
@@ -75,22 +74,6 @@ function applySanitizedEnv(sanitizedEnv: NodeJS.ProcessEnv): void {
}
}
function spawnDetachedApp(childArgs: string[], env: NodeJS.ProcessEnv): void {
const keepalive = resolveAppImageMountKeepaliveInvocation(env);
const child = keepalive
? spawn(keepalive.command, [...keepalive.args, ...childArgs], {
detached: true,
stdio: 'ignore',
env,
})
: spawn(process.execPath, childArgs, {
detached: true,
stdio: 'ignore',
env,
});
child.unref();
}
function resolveBundledWindowsMpvPluginEntrypoint(): string | undefined {
return (
resolvePackagedRuntimePluginPath({