tj / n

Node version management

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Add a new command (say `use`) to switch to preinstalled versions of Node.js

trivikr opened this issue · comments

Is your feature request related to a problem? Please describe.

There's no command for switching to specific pre-installed version of node.
The install command attempts to install latest semver version of requested version

Output on CodeBuild when command n 14 was run.

[Container] 2023/09/19 01:23:57 Running command n 14
curl: (28) Failed to connect to nodejs.org port 443 after 260269 ms: Couldn't connect to server

  Error: failed to download version index (https://nodejs.org/dist/index.tab)

[Container] 2023/09/19 01:28:18 Command did not exit successfully n 14 exit status 2
[Container] 2023/09/19 01:28:18 Phase complete: INSTALL State: FAILED
[Container] 2023/09/19 01:28:18 Phase context status code: COMMAND_EXECUTION_ERROR Message: Error while executing command: n 14. Reason: exit status 2

Describe the solution you'd like

Add a new command (say use) which just switches to preinstalled version

$ n use 14

Describe alternatives you've considered

  • Switch to fnm
  • Catch errors and retry using shell:
    for i in {1..5}; do n 14 && break || sleep 15; done

Additional context

We use n in release CI. And the installation used to fail sometimes because of 4XX from Node.js website.
We switched to creating a Docker Image for preinstalling Node.js versions, but noticed that Node.js website is still accessed when n attempts to switch to preinstalled versions.

Steps to repro

Install with network on

$ n 14
  installing : node-v14.21.3
       mkdir : /usr/local/n/versions/node/14.21.3
       fetch : https://nodejs.org/dist/v14.21.3/node-v14.21.3-darwin-x64.tar.xz
     copying : node/14.21.3
   installed : v14.21.3 (with npm 6.14.18)

Test with network off

$ n 14
curl: (6) Could not resolve host: nodejs.org

  Error: failed to download version index (https://nodejs.org/dist/index.tab)

Testing with fnm

$ fnm --version
fnm 1.35.1

Install with network on

$ fnm install 14
Installing Node v14.21.3 (x64)

Use with network off

$ node -v
v16.20.2

$ fnm use 14
Using Node v14.21.3

$ node -v
v14.21.3

Testing with nvm

$ nvm --version  
0.39.5

Install with network on

$ nvm install 18 
Downloading and installing node v18.18.0...
...
Now using node v18.18.0 (npm v9.8.1)
Creating default alias: default -> 18 (-> v18.18.0)

Use with network off

$ node -v
v16.20.2

$ nvm use 18
Now using node v18.18.0 (npm v9.8.1)

$ node -v
v18.18.0

A quick reply.

n requires the network to resolve a partial version or alias. You can install a previously downloaded version without accessing the network by specifying the full version number, like n install 18.16.0.

For an interactive install, running n gives you a menu of the downloaded versions. n ls lists the downloaded versions.

(There have been a few issues mentioning doing lookups against the local versions, I'll look for some later.)

You can install a previously downloaded version without accessing the network by specifying the full version number, like n install 18.16.0

The full version number is not available in our release CI.

We install latest version of Node.js in Docker Image, and specify just the major version when running the CI.
The CI doesn't have access to the full version number installed. It just wants to use the preinstalled version from Docker image.

With current code, you would do something like this to install latest version available in the docker container (no error checking):

VERSION=$(n ls | tail -n 1)
n $VERSION

Related past issues: #377 #404 #727 #776

Verified that the workaround (with grep for major version) works when there's no internet

Install with network on

$ n 20
  installing : node-v20.7.0
       mkdir : /usr/local/n/versions/node/20.7.0
       fetch : https://nodejs.org/dist/v20.7.0/node-v20.7.0-darwin-arm64.tar.xz
     copying : node/20.7.0
   installed : v20.7.0 to /usr/local/bin/node

$ node -v
v20.7.0

With network off

$ n 20
curl: (6) Could not resolve host: nodejs.org

  Error: failed to download version index (https://nodejs.org/dist/index.tab)

$ n $(n ls | grep /20 | tail -n 1)
     copying : node/20.7.0
   installed : v20.7.0 (with npm 10.1.0)

It would be awesome if this workaround can be added as a new command (like use) which can be called directly.

It would be awesome if this workaround can be added as a new command (like use)

The functionality requested

$ n --help
...
  n <version>                    Install Node.js <version> (downloading if necessary)
  n install <version>            Install Node.js <version> (downloading if necessary)
  n use <version>                Switch to pre-installed Node.js <version>
...

The behavior when the version is installed

$ n use 18
     copying : node/18.18.0
   installed : v18.18.0 (with npm 9.8.1)

The behavior when version is not installed, can be similar to that of fnm, i.e. interactive

$ n use 18
Can't find an installed Node version matching v18.x.x.
Do you want to install it? answer [y/n]: y
  installing : node-v18.18.0
       mkdir : /usr/local/n/versions/node/18.18.0
       fetch : https://nodejs.org/dist/v18.18.0/node-v18.18.0-darwin-arm64.tar.xz
     copying : node/18.18.0
   installed : v18.18.0 to /usr/local/bin/node

Although I quite like the clarity of a separate command (say use) to parallel install, it is by design limited to that one case. Many of the commands resolve a "version" by referring to index.tab over network: run, which, exec, and even rm.

Other approaches could be an option to not use the internet (say --offline), a prefix to refer to a downloaded version (say local/18), or caching index.tab for lookups. Thinking more about the prefix, probably limited to numeric versions as I don't think (say) local/auto is sensible.

Experiment adding --offline in #785.

Added --offline option in n v9.2.0