Lightweight Node.js version switching
Recently, I’ve been paying attention to the time it takes my shell’s
init script to complete. Bash is notoriously slow, but since it’s
popular in scripting use, I keep using it. This leaves me to optimize my
~/.bashrc
.
I program with Node.js frequently, so a Node.js version manager is an
essential tool. Upon investigating the execution time of my .bashrc
, I
found that loading nvm takes a lot of time:
400 ms for sourcing nvm.sh
is a way too big share of the time budget
I’d like to allocate for starting Bash in interactive mode. It’s a pity,
because nvm
is a quite nice tool.
An alternative for nvm
is nodenv:
I can manage with 70 ms. This is the tool I chose to use as my Node.js
version manager for a while. But because nodenv
utilizes shims to wrap
the executables of the selected Node.js version, a couple of problems
arise. The first is that after installing a new executable from global
npm package, you must remember to run nodenv rehash
to rebuild the
shims. Otherwise you can’t run the executable. The second is that you
lose access to the manual pages of the wrapped executables: a shim is an
indirection for the actual executable, causing man
’s manual page
search to miss the page. A demonstration of the problems:
I keep forgetting to run nodenv rehash
and I do would like to access
the manual pages of the executables of the selected Node.js version.
nvm
and nodenv
have a lot of features. While they are useful in some
scenarios, such as continuous integration setups, I’d be satisfied with
less in my development environment. The ability to install specific
Node.js versions and to switch between them easily, independently per
shell session, would be enough.
In the Ruby community, ruby-install and chruby tools provide just
these features, and nothing more. The former is for installing Rubies
and the latter for switching between them. What’s great about this
arrangement of separate tools is that the switcher, chruby
, is very
lightweight.
node-build, part of nodenv
project, is a dedicated Node.js
installer. It checks the digest of the downloaded Node.js package and
allows you to unpack it to any directory. This is good and I’ll keep
using it.
For the version switcher, I didn’t find anything I liked. sh-chnode is
written in the same spirit as chruby
, but includes some design
decisions I didn’t like personally.
I ended up writing my own version switcher, even though there’s already
so many of them. But this one is fast to load, does one thing well, and
is suitable for me. :) Naming is hard, so I just call it chnode
. Let’s
see it in action:
For me, chnode is the tool comparable to chruby
for Node.js
versions. Like chruby
, the primary mechanism of chnode
is to modify
the PATH
environment variable to include the path to the bin
subdirectory of the selected Node.js version. But unlike chruby
,
chnode
does not modify any Node.js specific environment variable
(there’s no need).
I didn’t implement auto-switching to chnode
. The feature would switch
Node.js version to the version specified in the .node-version
file if
the current working directory, or its parent, would have the file. You
might put such a file at a project’s root directory. chruby
has the
feature, but because I don’t use it, I dropped it.
chnode
supports GNU Bash and Zsh, has good test coverage, and
allows you to display the selected Node.js version in the shell prompt
with ease. It’s MIT licensed. See the README for more.
Finally, the total execution time of initializing my Bash
setup in interactive mode, including selecting a Node.js
version with chnode
: