Developing on a Mac – Part III – NodeJS

Categories:

I wrote Part I of this series to provide a foundation upon which to build a collection of minimal guides to developing software on a Mac. In this post let’s look at what needs to be installed on your Mac for developing NodeJS applications. If you haven’t read Part I, make sure you do and install:

  • Homebrew
  • Developer Tools

NodeJS

NodeJS can be installed and managing using a number of package managers, just like we saw with Ruby. Or, you can install it directly from nodejs.org. You can even install it with Homebrew!

Homebrew Install

Installing NodeJS with Homebrew is as simple as running brew install node in your terminal.

Both node (the NodeJS engine) and npm (Node Package Manager) are installed:

[code lang=text]
% node –version
v19.1.0

% npm –version
8.19.3
[/code]

Now to install a few node packages in the global environment:

[code lang=text]
npm install -g dotenv openssl
[/code]

Where’d they get installed?

[code lang=text]
$ npm list -g –depth 0 -p
/opt/homebrew/lib
/opt/homebrew/lib/node_modules/dotenv
/opt/homebrew/lib/node_modules/npm
/opt/homebrew/lib/node_modules/openssl
[/code]

Changing versions

It’s not uncommon to be developing with multiple NodeJS versions, especially in a professional environment. Installing and managing Node versions with Homebrew isn’t too difficult, if you make the decision to only have one version installed at a time. No joke.

[code lang=text]
% brew search node
==> Formulae
libbitcoin-node node-build node@14 nodebrew
linode-cli node-sass node@16 nodeenv
llnode node@10 node@18 nodenv
node node@12 node_exporter ode
[/code]

Recall that we installed v19.1.10. As it turns out that isn’t a Long Term Support (LTS) release. Let’s install v14.

[code lang=text]
brew uninstall node
brew install node@14
[/code]

You are undoubtedly protesting: “What about all of the cool command line tools I installed through npm?!” You should probably be keeping a list of those and reinstall them.

Using NodeJS.org

NodeJS.org hosts binary package installers for Node. You can install these packages by downloading and then double-clicking on them or via the command-line.

Installing via the command line uses the installer application:

[code lang=text]
sudo installer -pkg node-v18.12.1.pkg -target /
[/code]

If you’ve never used pkgutil before on your Mac, try it out!

[code lang=text]
% pkgutil –packages
com.apple.pkg.CLTools_SDK_macOS13
com.apple.pkg.CLTools_SDK_macOS12
com.apple.pkg.CLTools_Executables
com.apple.files.data-template
com.apple.pkg.MRTConfigData_10_15.16U4211
com.apple.pkg.CLTools_SwiftBackDeploy
com.apple.pkg.XProtectPayloads_10_15.16U4232
com.apple.pkg.CLTools_macOS_SDK
org.nodejs.npm.pkg
org.nodejs.node.pkg
[/code]

As promised, the NodeJS.org installs node in /usr/local/bin:

[code lang=text]
% which node
/usr/local/bin/node
[/code]

Let’s see where our modules are installed: npm install -g dotenv

[code lang=text]
npm ERR! Error: EACCES: permission denied, mkdir '/usr/local/lib/node_modules/dotenv'
[/code]

Oh! sudo access is required. And that’s why I’d stop right here. NodeJS installed in this manner is not going to support multiple versions and will make your development experience miserable.

Using nvm

A third method of installing NodeJS is through NVM, the Node Version Manager. Of course you can install nvm using their instructions, or use Homebrew.

[code lang=text]
% brew install nvm
Please note that upstream has asked us to make explicit managing
nvm via Homebrew is unsupported by them and you should check any
problems against the standard nvm install method prior to reporting.

You should create NVM's working directory if it doesn't exist:

mkdir ~/.nvm

Add the following to ~/.zshrc or your desired shell
configuration file:

export NVM_DIR="$HOME/.nvm"
[ -s "/opt/homebrew/opt/nvm/nvm.sh" ] && \. "/opt/homebrew/opt/nvm/nvm.sh" # This loads nvm
[ -s "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm" ] && \. "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm" # This loads nvm bash_completion

You can set $NVM_DIR to any location, but leaving it unchanged from
/opt/homebrew/opt/nvm will destroy any nvm-installed Node installations
upon upgrade/reinstall.

nvm list
N/A
iojs -> N/A (default)
node -> stable (-> N/A) (default)
unstable -> N/A (default)
[/code]

Once you’ve installed a NVM you can use nvm install to install a specific version.

[code lang=text]
nvm install 18
Downloading and installing node v18.12.1…
Downloading https://nodejs.org/dist/v18.12.1/node-v18.12.1-darwin-arm64.tar.xz…
######################################################################### 100.0%
Computing checksum with shasum -a 256
Checksums matched!
Now using node v18.12.1 (npm v8.19.2)
Creating default alias: default -> 18 (-> v18.12.1)

% which node
/Users/joe/.nvm/versions/node/v18.12.1/bin/node

% which npm

[/code]

And installing the dotenv package.

[code lang=text]
% npm install -g dotenv

% npm list -g –depth 0 -p
/Users/joe/.nvm/versions/node/v18.12.1/lib
/Users/joe/.nvm/versions/node/v18.12.1/lib/node_modules/corepack
/Users/joe/.nvm/versions/node/v18.12.1/lib/node_modules/dotenv
/Users/joe/.nvm/versions/node/v18.12.1/lib/node_modules/npm
[/code]

Creating a Basic Application

With NodeJS installed, let’s take it for a spin and write a “simple” application that reads data from a Postgres database.

[code lang=text]
% mkdir ~/projects/nodejs/simple_node_app
% cd ~/projects/nodejs/simple_node_app
% npm init -y
Wrote to /Users/joe/projects/nodejs/simple_node_app/package.json
[/code]

We’ll be using the pg, dotenv, and yargs packages.

[code lang=text]
npm install pg dotenv yargs –save-deps
[/code]

Of course, to communicate with a Postgres database we’ll need one! Here we’ll install Postgres, start it, and then create a new database, user, and grants for this example.

[code lang=text]
% brew install postgresql
% brew services start postgresql
% psql postgres
psql (14.6 (Homebrew))
Type "help" for help.

postgres=# create database simple_node_app_db;
postgres=# create user simple_node_app_user with password 'simple_node_app_pw';
postgres=# grant all privileges on database simple_node_app_db to simple_node_app_user;
postgres=# \q
[/code]

Back to our Node code. We’ll put the following in index.js:

You can try running this as is, but the connection to the database will fail. That can be fixed with a .env file which utilizes the pg default environment variables for the database, username, password, etc.

[code lang=text]
PGUSER=simple_node_app_user
PGPASSWORD=simple_node_app_password
PGHOST=localhost
PGDATABASE=simple_node_app_db
[/code]

[code lang=text]
% node index.js –username joe
Inserting user joe
Exiting…
[/code]

Which Installation Method to Use?

[table id=2 /]

 

I recommend using either Homebrew or NVM for installing and managing versions of NodeJS. Uninstalling the version provided by NodeJS.org is a pain in the ass, but can be done. I wouldn’t recommend the method
here, but rather use this method.

WARNING: sudo and rm -f ahead. Always read and get a feeling for what commands do before running them. You may consider commenting out the rm command to see what files are going to be removed.

followed by

and finally,

Leave a Reply

Your email address will not be published. Required fields are marked *