fix(install): require Node >=20.19/22.12 for the desktop build

The "Build desktop app" install step failed with an opaque "exit code 1"
on machines with an old Node, and nothing in the logs explained it.

Reproduced: on Node 20.5.1, `npm run pack`'s `vite build` crashes with

  You are using Node.js 20.5.1. Vite requires Node.js version 20.19+ or 22.12+.
  SyntaxError: The requested module 'node:util' does not provide an
  export named 'styleText'

Vite 8 (rolldown) imports node:util.styleText, which doesn't exist before
Node 20.12, so the build dies before producing the app. The installer's
check_node / Test-Node accepted ANY pre-existing Node with no version
floor, so a too-old system Node was used for the build instead of the
bundled Node 22.

Add a version floor (^20.19 || >=22.12) to check_node (install.sh) and
Test-Node (install.ps1): a too-old system Node is replaced with the
Hermes-managed Node 22 LTS, and the desktop stage re-resolves Node so the
build always runs on a satisfying version. Declare the same range in
apps/desktop/package.json engines.

Verified: build succeeds on Node 22, fails on 20.5.1 with the error above;
the floor logic matches Vite's range across boundary versions (20.18/20.19,
21.x, 22.11/22.12).
This commit is contained in:
Brooklyn Nicholson
2026-06-03 09:19:04 -05:00
parent 214b7e070f
commit 1dca7c6207
3 changed files with 71 additions and 29 deletions
+31 -13
View File
@@ -702,26 +702,43 @@ check_git() {
exit 1
}
# The desktop build runs Vite ^8, which refuses to start on Node outside
# `^20.19 || >=22.12` — older Node lacks `node:util.styleText`, so `vite build`
# crashes with a SyntaxError that surfaces only as the opaque "Build desktop
# app … exit code 1" install failure. Returns 0 when the given `node --version`
# string clears that floor; anything below it is replaced with the Hermes-
# managed Node $NODE_VERSION LTS.
node_satisfies_build() {
local ver="${1#v}"
local major="${ver%%.*}"
local minor="${ver#*.}"; minor="${minor%%.*}"
case "$major" in ''|*[!0-9]*) return 1 ;; esac
case "$minor" in ''|*[!0-9]*) minor=0 ;; esac
if [ "$major" -eq 20 ] && [ "$minor" -ge 19 ]; then return 0; fi
if [ "$major" -ge 22 ] && { [ "$major" -gt 22 ] || [ "$minor" -ge 12 ]; }; then return 0; fi
return 1
}
check_node() {
log_info "Checking Node.js (for browser tools)..."
if command -v node &> /dev/null; then
local found_ver=$(node --version)
log_success "Node.js $found_ver found"
if command -v node &> /dev/null && node_satisfies_build "$(node --version)"; then
log_success "Node.js $(node --version) found"
HAS_NODE=true
return 0
fi
# Check our own managed install from a previous run
if [ -x "$HERMES_HOME/node/bin/node" ]; then
# Prefer a Hermes-managed Node from a previous run over a too-old system one.
if [ -x "$HERMES_HOME/node/bin/node" ] && node_satisfies_build "$("$HERMES_HOME/node/bin/node" --version)"; then
export PATH="$HERMES_HOME/node/bin:$PATH"
local found_ver=$("$HERMES_HOME/node/bin/node" --version)
log_success "Node.js $found_ver found (Hermes-managed)"
log_success "Node.js $("$HERMES_HOME/node/bin/node" --version) found (Hermes-managed)"
HAS_NODE=true
return 0
fi
if [ "$DISTRO" = "termux" ]; then
if command -v node &> /dev/null; then
log_warn "Node.js $(node --version) is too old for the desktop build (need ^20.19 or >=22.12) — installing Hermes-managed Node $NODE_VERSION LTS..."
elif [ "$DISTRO" = "termux" ]; then
log_info "Node.js not found — installing Node.js via pkg..."
else
log_info "Node.js not found — installing Node.js $NODE_VERSION LTS..."
@@ -2235,11 +2252,12 @@ install_desktop() {
# (--include-desktop / 'desktop' stage), so a missing toolchain is a hard
# failure, not a silent skip — a silent skip yields a "complete" install
# with no app and a confusing "couldn't find a built desktop" at launch.
# Try the Hermes-managed Node first (check_node adds $HERMES_HOME/node/bin
# to PATH or installs it) before giving up.
if ! command -v npm >/dev/null 2>&1; then
check_node
fi
# Always re-resolve Node here. Stages run in separate processes, so we can't
# trust an earlier check; more importantly check_node now enforces the build
# floor (^20.19 || >=22.12) and prepends the Hermes-managed Node to PATH, so
# the build never runs on a too-old system Node — the cause of the opaque
# "Build desktop app … exit code 1" failure (Vite crashes on old Node).
check_node
if ! command -v npm >/dev/null 2>&1; then
log_error "Cannot build desktop app: Node.js / npm unavailable"
log_info "Install Node.js and retry: cd $desktop_dir && npm run pack"