From c008f41bb979257e0467e771550fd67d77ce75c0 Mon Sep 17 00:00:00 2001 From: ethernet Date: Thu, 9 Jul 2026 14:26:14 -0400 Subject: [PATCH] fix(desktop): stage-native-deps falls back to electron-rebuild when no native binary exists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When neither a prebuild nor a compiled build/Release/*.node is found for the target platform-arch, stage-native-deps.mjs now runs electron-rebuild -f -w node-pty to compile one from source before re-copying build/Release into the staged dist. This makes the staging script self-sufficient — it always produces a working native binary dir regardless of whether npm ci --ignore-scripts skipped postinstall or whether node-pty publishes prebuilds for the target (e.g. linux-x64 has no prebuild). --- apps/desktop/scripts/stage-native-deps.mjs | 50 +++++++++++++++++----- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/apps/desktop/scripts/stage-native-deps.mjs b/apps/desktop/scripts/stage-native-deps.mjs index 02e5e2ad1c49..cdd621bf2ff1 100644 --- a/apps/desktop/scripts/stage-native-deps.mjs +++ b/apps/desktop/scripts/stage-native-deps.mjs @@ -20,6 +20,7 @@ import { readdirSync, rmSync } from 'node:fs' +import { spawnSync } from 'node:child_process' import { isMain } from './utils.mjs' const here = dirname(fileURLToPath(import.meta.url)) @@ -92,11 +93,6 @@ export function stageNodePty({ platform = process.platform, arch = process.arch // lib/**/*.js — the JS surface node-pty's `main` points into. copyGlobByExt(join(srcRoot, 'lib'), join(destRoot, 'lib'), ['.js']) - // build/Release/* — present when node-pty was compiled locally - // (e.g. no prebuild available for this Electron ABI/platform combo). - // Some installs won't have this at all if prebuild-install succeeded. - copyBuildRelease(join(srcRoot, 'build/Release'), join(destRoot, 'build/Release')) - // prebuilds/-/* — the prebuild-install payload for the // *target* we're packaging, not necessarily the host running this script. // Explicit extensions only, to skip the ~25MB of Windows .pdb symbols @@ -119,13 +115,45 @@ export function stageNodePty({ platform = process.platform, arch = process.arch chmodSync(join(destPrebuild, entry.name), 0o775) } } - } else { - console.warn( - `[stage-native-deps] no prebuild found at prebuilds/${platform}-${arch} for node-pty. ` + - `If build/Release/* above is also empty, this target will fail at runtime. ` + - `Run "npx electron-rebuild -w node-pty" for this target, or check that ` + - `node-pty's published prebuilds cover ${platform}-${arch}.` + } + + // build/Release/* — present when node-pty was compiled locally + // (e.g. no prebuild available for this Electron ABI/platform combo). + // Some installs won't have this at all if prebuild-install succeeded. + const buildReleaseDir = join(srcRoot, 'build/Release') + copyBuildRelease(buildReleaseDir, join(destRoot, 'build/Release')) + + // If neither a prebuild nor build/Release produced a .node binary for this + // target, run electron-rebuild to compile one from source. This happens on + // CI (npm ci --ignore-scripts skips postinstall) and on platforms where + // node-pty doesn't publish prebuilds (e.g. linux-x64). + const stagedDirs = [ + join(destRoot, 'prebuilds', `${platform}-${arch}`), + join(destRoot, 'build/Release') + ] + const hasNativeBinary = stagedDirs.some(dir => { + if (!existsSync(dir)) return false + return readdirSync(dir, { recursive: true }).some(name => String(name).endsWith('.node')) + }) + + if (!hasNativeBinary) { + console.log( + `[stage-native-deps] no prebuilt or compiled native binary for ${platform}-${arch}; ` + + `running electron-rebuild to compile from source...` ) + const result = spawnSync( + process.execPath, + ['../../node_modules/.bin/electron-rebuild', '-f', '-w', 'node-pty'], + { cwd: projectRoot, stdio: 'inherit' } + ) + if (result.status !== 0) { + throw new Error( + `electron-rebuild failed for ${platform}-${arch} (exit ${result.status}). ` + + `Cannot stage node-pty without a native binary.` + ) + } + // Re-copy build/Release after electron-rebuild populated it. + copyBuildRelease(buildReleaseDir, join(destRoot, 'build/Release')) } console.log(`[stage-native-deps] staged node-pty (${platform}-${arch}) -> ${destRoot}`)