Published 2022-03-01.
Last modified 2024-08-25.
Time to read: 4 minutes.
posts
collection, categorized under JavaScript.
Node.js
,
a JavaScript runtime, is not my favorite programming environment.
Originally released 15 years ago by
Ryan Dahl,
a software engineer at Google,
it’s historical disregard for
security
and stability is problematic.
However, node.js
has significant traction,
especially amongst Millennial software technologists,
and is used by many Ruby and Scala projects for HTML
asset pipelines.
I put together these notes for installing and maintaining node.js
on Ubuntu/WSL using a virtualized version manager.
Why Virtualize Node.js?
It is better to use virtualized user- and project-specific node.js
instances,
instead of working with a system-wide installation of node.js
.
This allows you to install and upgrade node.js
packages without using supervisor privileges.
Also, virtualized instances allows you to work on many different independent node.js
projects
at the same time, without package version collisions.
Docker
is over-sold.
It adds unnecessary complexity to software projects.
Instead of virtualizing the entire software environment,
as docker
attempts to do,
virtualizing the programming environment with node.js nvm
,
Python venv
,
or Ruby rbenv
are much easier and more productive approaches.
I think docker
has been pushed hard in the media because it is a gateway technology to
PaSS.
This is a trend that PaSS vendors like AWS and Azure want to encourage, but
customers are pushing back.
Nvm
Nvm
, the Node Version Manager, makes it easy to install multiple virtualized
node.js
instances,
and to easily switch between them.
Nvm
retains a unique set of installed packages for each node.js
instance.
The node.js
version in each instance is distinct.
Nvm
is installed and updated as follows:
$ curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 14926 100 14926 0 0 84806 0 --:--:-- --:--:-- --:--:-- 85291 => nvm is already installed in /home/mslinn/.nvm, trying to update using git => => Compressing and cleaning up git repository => nvm source string already in /home/mslinn/.bashrc => bash_completion source string already in /home/mslinn/.bashrc => Close and reopen your terminal to start using nvm or run the following to use it now: export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion $ export NVM_DIR="$HOME/.nvm"
$ [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
$ [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
View the currently installed versions of node.js
:
$ nvm list -> system iojs -> N/A (default) node -> stable (-> N/A) (default) unstable -> N/A (default)
View the very long list of available versions of node.js
like this:
$ nvm list-remote v17.7.0 v17.7.1 v17.7.2 v17.8.0 v17.9.0 v17.9.1 v18.0.0 v18.1.0 v18.2.0 v18.3.0 v18.4.0 v18.5.0 v18.6.0 v18.7.0 v18.8.0 v18.9.0 v18.9.1 v18.10.0 v18.11.0 v18.12.0 (LTS: Hydrogen) v18.12.1 (LTS: Hydrogen) v18.13.0 (Latest LTS: Hydrogen) v19.0.0 v19.0.1 v19.1.0 v19.2.0 v19.3.0 v19.4.0 v19.5.0
Using Nvm to Install Node.js
Install the latest release of node.js
using nvm
:
$ nvm install node Downloading and installing node v19.5.0... Downloading https://nodejs.org/dist/v19.5.0/node-v19.5.0-linux-x64.tar.xz... ##################################################################### 100.0% Computing checksum with sha256sum Checksums matched! Now using node v19.5.0 (npm v9.3.1) Creating default alias: default -> node (-> v19.5.0)
In the above example, node
is an alias for “the latest version of node.js
”.
To install a specific version of node.js
, for example 18.13.0:
$ nvm install 18.13.0
Yarn
Whether you use nvm
as your node.js
virtualization mechanism,
you also need a node.js
package manager to install and maintain project dependencies.
Yarn
supposedly stands for Yet Another Resource Negotiator,
and it is a package manager like npm
,
described next.
It was developed by Facebook and is now open-source.
Yarn
was developed to address npm
’s performance and security issues.
The name actually suggests the major advantage yarn
has over its predecessor, npm
:
multi-threading instead of single-threading.
Yarn generates a yarn.lock
file, which helps easy merges.
The merges are predictable.
Yarn
caches every package it has downloaded, so it never needs to download the same package again.
It also does almost everything concurrently to maximize resource utilization.
This means faster installs.
Yarn
guarantees that any installation that works on one system will work exactly the same on another system, unlike npm
.
The notes for the yarn
package state that
Yarn
was inspired by Bundler and
Cargo,
and is nearly command-line compatible with npm
.
Yarn
introduces the zero-install concept, which means that a project should be able to be used as soon as it is cloned.
It uses Plug’n’Play to resolve dependencies via the yarn
cache folder and not from node_modules
.
The cache folder is by default stored within your project folder, in .yarn/cache
.
Installing Yarn
To install yarn
on Ubuntu:
$ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | \ sudo apt-key add - $ echo "deb https://dl.yarnpkg.com/debian/ stable main" | \ sudo tee /etc/apt/sources.list.d/yarn.list $ sudo apt update && sudo apt install yarn
Configuring a Project With Yarn
The yarn init
command initiates an interactive session that creates a package.json
file.
$ cd /path/to/my/node/project
$ yarn init yarn init v1.22.19 question name (node): blah question version (1.0.0): 0.1.0 question description: Just a little song I wrote question entry point (index.js): question repository url: https://github.com/mslinn/blah question author: Mike Slinn question license (MIT): question private: success Saved package.json Done in 48.29s.
The above dialog creates package.json
in the current directory:
{ "name": "blah", "version": "0.1.0", "description": "Just a little song I wrote", "main": "index.js", "repository": "https://github.com/mslinn/blah", "author": "Mike Slinn", "license": "MIT" }
Adding a Dependency to a Project
Yarn stores dependencies locally. If the proper version is present locally,
it is fetched from the disk during a yarn add
command, otherwise it is downloaded.
This is the general format of the command to add a dependency to a node.js
project using yarn
:
$ yarn add package_name
To add a specific version of a package:
$ yarn add package_name@version_number
To install a global package, the general formats are:
$ yarn global add package_name $ yarn global add package_name@version_number
Yarn and Git
The official Yarn docs say to add the following to
.gitignore
for git projects that use yarn
:
.yarn/* !.yarn/cache !.yarn/patches !.yarn/plugins !.yarn/releases !.yarn/sdks !.yarn/versions
Installing Dependencies
To install all the dependencies in a node.js
project,
type yarn
or yarn install
:
$ cd /path/to/my/project $ yarn
Updating Dependencies
To upgrade all the dependencies in a node.js
project,
use yarn upgrade
:
$ cd /path/to/my/project $ yarn upgrade
Npm
Npm
is the original package manager for the family of JavaScript programming languages,
and it is still the default package manager for node.js
.
This will likely change as yarn
matures.
Npm
helps install libraries, plugins, frameworks and applications.
It consists of a command-line client, also called npm
,
and an online database of public and paid-for private packages called the npm
registry.
Npm
fetches dependencies from the npm
registry for every npm install
command.
Npm
generates a package-lock.json
file.
The layout of this file is a trade-off between determinism and simplicity.
The same node_modules/
folder will be generated by every version of npm
.
Every dependency will have a version number associated with it in the package-lock
file.
Npm vs. Yarn
When using npm install
, dependencies are installed sequentially, one after another.
The output logs in the terminal are informative but a bit hard to read.
To install the packages with Yarn, run the yarn
command.
Yarn installs packages in parallel, which is one of the reasons it is quicker than npm.
For more information, see Difference between npm and yarn.
Install Npm With a Node Version Manager
Follow these instructions. In summary:
$ mkdir ~/.npm-global
$ npm config set prefix ~/.npm-global
$ cat >> ~/.bashrc <<EOF export PATH="$HOME/.npm-global/bin:$PATH"
export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" 1>&2 # Loads nvm EOF
$ source ~/.bashrc
$ curl -fsSL https://deb.nodesource.com/setup_21.x | \ sudo -E bash - && \ sudo apt-get install -y nodejs
Install A Global Package
To install a global package, the command template for npm
is:
$ npm install -g package_name[@version_number]
For example:
$ npm install -g broken-link-checker npm WARN deprecated calmcard@0.1.1: no longer maintained npm WARN deprecated nopter@0.3.0: try optionator npm WARN deprecated uuid@2.0.3: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. npm WARN deprecated urlobj@0.0.11: use universal-url, minurl, relateurl, url-relation added 104 packages, and audited 105 packages in 5s
Update NPM
To update NPM:
$ npm install -g npm@latest changed 13 packages in 4s