fix(install): make npm install -g packages reachable on PATH - #46085
Conversation
When the installer falls back to a bundled Node under $HERMES_HOME/node, npm's default global prefix is that Node dir, so `npm install -g <pkg>` drops the package binary in $HERMES_HOME/node/bin. Only node/npm/npx are symlinked into the command link dir (~/.local/bin, /usr/local/bin, or $PREFIX/bin) — so user-installed global package binaries are NOT on PATH and can't be run, even though `npm i -g` reports success. They also get wiped on every Node upgrade (the dir is rm -rf'd and re-extracted). Redirect the bundled Node's npm global prefix to the command link dir's parent, so global bins land in the link dir (already on PATH, alongside node/npm/npx) and survive Node upgrades. Scoped to the bundled Node via its prefix-local global npmrc ($HERMES_HOME/node/etc/npmrc), so the user's other Node installs and their ~/.npmrc are untouched. Hermes's own global installs (agent-browser) pass an explicit --prefix and are unaffected.
Guards that install.sh and node-bootstrap.sh redirect the bundled Node's npm global prefix to the command link dir's parent via a prefix-local global npmrc, so `npm install -g` binaries land on PATH instead of the off-PATH $HERMES_HOME/node/bin.
The initial fix only wrote the prefix npmrc on a fresh Node install, so pre-existing bundled-Node installs (Node already present) were not repaired by re-running the installer — install_node/ensure_node skip when Node is already up to date. Extract the redirect into an idempotent helper (configure_managed_node_npm_prefix / _nb_configure_npm_prefix) that no-ops when there's no Hermes-managed npm, and call it unconditionally from check_node (install.sh) and at the top of ensure_node (node-bootstrap.sh). Re-running the install command now repairs an affected install in place, not just brand-new ones.
|
Reviewed and verified end-to-end — this is a clean fix for a real bug. Premise confirmed. On the bundled-Node fallback, npm's default global prefix is the Node dir, so Mechanism is correct and well-scoped. Writing Idempotent / repairs existing installs. The no-op guard ( Validation:
No issues found. Plan: salvage onto current |
…obal-npm-path fix(install): make `npm install -g` packages reachable on PATH
…obal-npm-path fix(install): make `npm install -g` packages reachable on PATH
…obal-npm-path fix(install): make `npm install -g` packages reachable on PATH
…obal-npm-path fix(install): make `npm install -g` packages reachable on PATH
…obal-npm-path fix(install): make `npm install -g` packages reachable on PATH
…obal-npm-path fix(install): make `npm install -g` packages reachable on PATH
…obal-npm-path fix(install): make `npm install -g` packages reachable on PATH
…obal-npm-path fix(install): make `npm install -g` packages reachable on PATH
What does this PR do?
Fixes "I can
npm i -g <pkg>but the package isn't usable on the command line" after a quick install — reported by a user whose globally-installed npm binaries were not onPATH.Root cause
When the installer can't find a suitable system Node, it installs a bundled Node into
$HERMES_HOME/node/and symlinks onlynode,npm,npxinto the command link dir (~/.local/bin,/usr/local/bin, or$PREFIX/bin), which it ensures is onPATH.But the bundled Node's npm uses its default global prefix, which is the Node install dir:
So
npm install -g <pkg>drops the package binary in$HERMES_HOME/node/bin/<pkg>— a directory that is not onPATH(only the link dir is). The user's global binaries are therefore unreachable even thoughnpm i -gsucceeds. Worse,$HERMES_HOME/nodeisrm -rf'd and re-extracted on every Node upgrade, so those globals are also wiped.Reproduced on a real Hermes-managed install:
The fix
Redirect the bundled Node's npm global prefix to the command link dir's parent, so global bins land in the link dir itself — already on
PATH, alongsidenode/npm/npx, and surviving Node upgrades:~/.local/binuser install → prefix~/.local→ bins in~/.local/bin✅/usr/local→ bins in/usr/local/bin✅$PREFIX→ bins in$PREFIX/bin✅It's written to the bundled Node's prefix-local global npmrc (
$HERMES_HOME/node/etc/npmrc, npm's defaultglobalconfigfor that Node), so it is scoped to the Hermes-managed Node only — the user's other Node installs and their~/.npmrcare untouched. Hermes's own global install (agent-browser) passes an explicit--prefix "$HERMES_HOME/node"(CLI overrides config) and is unaffected.Verified end-to-end against a real bundled Node: with the redirect,
npm prefix -greturns~/.localand~/.local/binis confirmed onPATH.The same fix is applied to both bundled-install paths:
scripts/install.sh(install_node) andscripts/lib/node-bootstrap.sh(_nb_install_bundled_node).Type of Change
Changes Made
scripts/install.sh: after symlinking node/npm/npx, writeprefix=<link-dir parent>to$HERMES_HOME/node/etc/npmrc.scripts/lib/node-bootstrap.sh: same redirect in the bundled-Node fallback.tests/test_install_sh_node_global_prefix.py: assert both scripts perform the redirect.How to Test
scripts/run_tests.sh tests/test_install_sh_node_global_prefix.py # Manual: on a bundled-Node install, `npm i -g cowsay && cowsay hi` now works.