165 lines · 4.5 KB · JavaScript
RawDownload
import { spawn } from "node:child_process";import fs from "node:fs";import net from "node:net";import path from "node:path"; const port = Number(process.env.ELECTRON_RENDERER_PORT ?? 5173);const STARTUP_TIMEOUT_MS = Number(process.env.T3CODE_ELECTRON_STARTUP_TIMEOUT_MS ?? 120_000); async function canConnect(host, probePort, timeoutMs = 1_000) {  return new Promise((resolve) => {    const socket = new net.Socket();    let settled = false;     const finish = (value) => {      if (settled) return;      settled = true;      socket.destroy();      resolve(value);    };     socket.setTimeout(timeoutMs);    socket.once("connect", () => finish(true));    socket.once("timeout", () => finish(false));    socket.once("error", () => finish(false));    socket.connect(probePort, host);  });} const f = (p) => path.join(import.meta.dirname, "..", p); function waitForDesktopBundles(timeoutMs) {  const FRESHNESS_GRACE_MS = 10_000;  const startedAt = Date.now();  const bundleFiles = [    { path: f("dist-electron/main.mjs"), requireFresh: true },    { path: f("dist-electron/preload.cjs"), requireFresh: true },    { path: f("../server/dist/index.mjs"), requireFresh: false },  ];   return new Promise((resolve, reject) => {    const tick = () => {      const missing = [];      const stale = [];       for (const bundleFile of bundleFiles) {        if (!fs.existsSync(bundleFile.path)) {          missing.push(bundleFile.path);          continue;        }        if (!bundleFile.requireFresh) {          continue;        }        try {          const stat = fs.statSync(bundleFile.path);          if (stat.mtimeMs < startedAt - FRESHNESS_GRACE_MS) {            stale.push(bundleFile.path);          }        } catch {          missing.push(bundleFile.path);        }      }       if (missing.length === 0 && stale.length === 0) {        resolve();        return;      }       if (Date.now() - startedAt >= timeoutMs) {        const parts = [];        if (missing.length > 0) {          parts.push(`missing: ${missing.join(", ")}`);        }        if (stale.length > 0) {          parts.push(`stale: ${stale.join(", ")}`);        }        reject(          new Error(            `[dev-electron] timed out after ${timeoutMs}ms waiting for bundles (${parts.join("; ")})`,          ),        );        return;      }       setTimeout(tick, 250);    };     tick();  });} function waitForDevServer(probePort, timeoutMs) {  const startedAt = Date.now();  const candidates = [    { host: "127.0.0.1", url: `http://127.0.0.1:${probePort}` },    { host: "::1", url: `http://[::1]:${probePort}` },    { host: "localhost", url: `http://localhost:${probePort}` },  ];   return new Promise((resolve, reject) => {    const tick = () => {      void Promise.all(        candidates.map(async (candidate) => ({          candidate,          connected: await canConnect(candidate.host, probePort),        })),      )        .then((results) => {          const ready = results.find((entry) => entry.connected);          if (ready) {            resolve(ready.candidate.url);            return;          }           if (Date.now() - startedAt >= timeoutMs) {            reject(              new Error(                `[dev-electron] timed out after ${timeoutMs}ms waiting for renderer dev server on port ${probePort}`,              ),            );            return;          }           setTimeout(tick, 250);        })        .catch((error) => {          reject(error);        });    };     tick();  });} console.log("[dev-electron] waiting for desktop/server bundles");await waitForDesktopBundles(STARTUP_TIMEOUT_MS); console.log(`[dev-electron] waiting for renderer dev server on port ${port}`);const devServerUrl = await waitForDevServer(port, STARTUP_TIMEOUT_MS);console.log(`[dev-electron] launching electron with renderer url ${devServerUrl}`); const command = process.platform === "win32" ? "electronmon.cmd" : "electronmon";const childEnv = { ...process.env };delete childEnv.ELECTRON_RUN_AS_NODE; if (process.platform === "linux" && !childEnv.ELECTRON_DISABLE_SANDBOX) {  childEnv.ELECTRON_DISABLE_SANDBOX = "1";  console.log("[dev-electron] enabling ELECTRON_DISABLE_SANDBOX=1 on Linux");} const child = spawn(command, ["dist-electron/main.mjs"], {  stdio: "inherit",  env: {    ...childEnv,    VITE_DEV_SERVER_URL: devServerUrl,  },}); child.on("exit", (code) => {  process.exit(code ?? 0);}); child.on("error", (error) => {  console.error("[dev-electron] failed to launch electronmon:", error.message);  process.exit(1);});