Skip to content

Commit 1dca7c6

Browse files
committed
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).
1 parent 214b7e0 commit 1dca7c6

3 files changed

Lines changed: 71 additions & 29 deletions

File tree

apps/desktop/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
"author": "Nous Research",
88
"type": "module",
99
"main": "electron/main.cjs",
10+
"engines": {
11+
"node": "^20.19.0 || >=22.12.0"
12+
},
1013
"scripts": {
1114
"dev": "concurrently -k \"npm:dev:renderer\" \"npm:dev:electron\"",
1215
"dev:fake-boot": "cross-env HERMES_DESKTOP_BOOT_FAKE=1 HERMES_DESKTOP_BOOT_FAKE_STEP_MS=650 npm run dev",

scripts/install.ps1

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -714,27 +714,47 @@ function Set-GitBashEnvVar {
714714
Write-Info "If needed, set HERMES_GIT_BASH_PATH manually to your bash.exe path."
715715
}
716716

717+
# The desktop build runs Vite ^8, which refuses to start on Node outside
718+
# `^20.19 || >=22.12` -- older Node lacks node:util.styleText, so `vite build`
719+
# crashes with a SyntaxError that surfaces only as the opaque "Build desktop
720+
# app ... exit code 1" install failure. Returns $true when a `node --version`
721+
# string clears that floor.
722+
function Test-NodeVersionOk {
723+
param([string]$Version)
724+
try {
725+
$v = [version]($Version -replace '^v', '' -replace '-.*$', '')
726+
} catch {
727+
return $false
728+
}
729+
if ($v.Major -eq 20 -and $v.Minor -ge 19) { return $true }
730+
if ($v.Major -ge 22 -and ($v.Major -gt 22 -or $v.Minor -ge 12)) { return $true }
731+
return $false
732+
}
733+
717734
function Test-Node {
718735
Write-Info "Checking Node.js (for browser tools)..."
719736

720737
if (Get-Command node -ErrorAction SilentlyContinue) {
721738
$version = node --version
722-
Write-Success "Node.js $version found"
723-
$script:HasNode = $true
724-
return $true
739+
if (Test-NodeVersionOk $version) {
740+
Write-Success "Node.js $version found"
741+
$script:HasNode = $true
742+
return $true
743+
}
744+
Write-Warn "Node.js $version is too old for the desktop build (need ^20.19 or >=22.12)"
725745
}
726746

727-
# Check our own managed install from a previous run
747+
# Prefer a Hermes-managed Node from a previous run over a too-old system one.
728748
$managedNode = "$HermesHome\node\node.exe"
729-
if (Test-Path $managedNode) {
749+
if ((Test-Path $managedNode) -and (Test-NodeVersionOk (& $managedNode --version))) {
730750
$version = & $managedNode --version
731751
$env:Path = "$HermesHome\node;$env:Path"
732752
Write-Success "Node.js $version found (Hermes-managed)"
733753
$script:HasNode = $true
734754
return $true
735755
}
736756

737-
Write-Info "Node.js not found -- installing Node.js $NodeVersion LTS..."
757+
Write-Info "Installing Hermes-managed Node.js $NodeVersion LTS..."
738758

739759
# Try the portable-zip path FIRST -- no UAC, no admin, no winget MSI.
740760
# winget install OpenJS.NodeJS.LTS triggers a system-wide MSI install
@@ -1906,16 +1926,17 @@ function Install-Desktop {
19061926
# so an "unpacked" build (electron-builder --dir) is enough — we
19071927
# don't need to produce an NSIS/MSI artifact here.
19081928

1909-
if (-not $HasNode) {
1910-
# Cross-process driver mode: each `-Stage NAME` invocation runs in a
1911-
# fresh PowerShell process, so $script:HasNode set by Stage-Node
1912-
# in the previous process isn't visible. Re-detect rather than
1913-
# trusting the global.
1914-
if (-not (Get-Command npm -ErrorAction SilentlyContinue)) {
1915-
Write-Warn "Skipping desktop build (Node.js / npm not on PATH)"
1916-
$script:_StageSkippedReason = "Node.js not available"
1917-
return
1918-
}
1929+
# Always re-resolve Node here. Stages run in separate PowerShell processes,
1930+
# so $script:HasNode from Stage-Node isn't visible; more importantly Test-Node
1931+
# enforces the build floor (^20.19 || >=22.12) and prepends the Hermes-managed
1932+
# Node to PATH, so the build never runs on a too-old system Node -- the cause
1933+
# of the opaque "Build desktop app ... exit code 1" failure (Vite crashes on
1934+
# old Node).
1935+
Test-Node | Out-Null
1936+
if (-not (Get-Command npm -ErrorAction SilentlyContinue)) {
1937+
Write-Warn "Skipping desktop build (Node.js / npm not on PATH)"
1938+
$script:_StageSkippedReason = "Node.js not available"
1939+
return
19191940
}
19201941

19211942
$desktopDir = "$InstallDir\apps\desktop"

scripts/install.sh

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -702,26 +702,43 @@ check_git() {
702702
exit 1
703703
}
704704

705+
# The desktop build runs Vite ^8, which refuses to start on Node outside
706+
# `^20.19 || >=22.12` — older Node lacks `node:util.styleText`, so `vite build`
707+
# crashes with a SyntaxError that surfaces only as the opaque "Build desktop
708+
# app … exit code 1" install failure. Returns 0 when the given `node --version`
709+
# string clears that floor; anything below it is replaced with the Hermes-
710+
# managed Node $NODE_VERSION LTS.
711+
node_satisfies_build() {
712+
local ver="${1#v}"
713+
local major="${ver%%.*}"
714+
local minor="${ver#*.}"; minor="${minor%%.*}"
715+
case "$major" in ''|*[!0-9]*) return 1 ;; esac
716+
case "$minor" in ''|*[!0-9]*) minor=0 ;; esac
717+
if [ "$major" -eq 20 ] && [ "$minor" -ge 19 ]; then return 0; fi
718+
if [ "$major" -ge 22 ] && { [ "$major" -gt 22 ] || [ "$minor" -ge 12 ]; }; then return 0; fi
719+
return 1
720+
}
721+
705722
check_node() {
706723
log_info "Checking Node.js (for browser tools)..."
707724

708-
if command -v node &> /dev/null; then
709-
local found_ver=$(node --version)
710-
log_success "Node.js $found_ver found"
725+
if command -v node &> /dev/null && node_satisfies_build "$(node --version)"; then
726+
log_success "Node.js $(node --version) found"
711727
HAS_NODE=true
712728
return 0
713729
fi
714730

715-
# Check our own managed install from a previous run
716-
if [ -x "$HERMES_HOME/node/bin/node" ]; then
731+
# Prefer a Hermes-managed Node from a previous run over a too-old system one.
732+
if [ -x "$HERMES_HOME/node/bin/node" ] && node_satisfies_build "$("$HERMES_HOME/node/bin/node" --version)"; then
717733
export PATH="$HERMES_HOME/node/bin:$PATH"
718-
local found_ver=$("$HERMES_HOME/node/bin/node" --version)
719-
log_success "Node.js $found_ver found (Hermes-managed)"
734+
log_success "Node.js $("$HERMES_HOME/node/bin/node" --version) found (Hermes-managed)"
720735
HAS_NODE=true
721736
return 0
722737
fi
723738

724-
if [ "$DISTRO" = "termux" ]; then
739+
if command -v node &> /dev/null; then
740+
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..."
741+
elif [ "$DISTRO" = "termux" ]; then
725742
log_info "Node.js not found — installing Node.js via pkg..."
726743
else
727744
log_info "Node.js not found — installing Node.js $NODE_VERSION LTS..."
@@ -2235,11 +2252,12 @@ install_desktop() {
22352252
# (--include-desktop / 'desktop' stage), so a missing toolchain is a hard
22362253
# failure, not a silent skip — a silent skip yields a "complete" install
22372254
# with no app and a confusing "couldn't find a built desktop" at launch.
2238-
# Try the Hermes-managed Node first (check_node adds $HERMES_HOME/node/bin
2239-
# to PATH or installs it) before giving up.
2240-
if ! command -v npm >/dev/null 2>&1; then
2241-
check_node
2242-
fi
2255+
# Always re-resolve Node here. Stages run in separate processes, so we can't
2256+
# trust an earlier check; more importantly check_node now enforces the build
2257+
# floor (^20.19 || >=22.12) and prepends the Hermes-managed Node to PATH, so
2258+
# the build never runs on a too-old system Node — the cause of the opaque
2259+
# "Build desktop app … exit code 1" failure (Vite crashes on old Node).
2260+
check_node
22432261
if ! command -v npm >/dev/null 2>&1; then
22442262
log_error "Cannot build desktop app: Node.js / npm unavailable"
22452263
log_info "Install Node.js and retry: cd $desktop_dir && npm run pack"

0 commit comments

Comments
 (0)