Node.js notes
/docs/gears/developer/middleware-notes/nodejs/
Node.js versions
It seems every Node.js application requires a different Node.js version. There is the most recent version of Node.js, the most recent LTS (“long-term stable”) version, and typically several older LTS versions are also still in widespread use. Some apps even depend on specific minor or patch releases.
UBOS provides the latest LTS version in a package but, realistically, UBOS cannot bundle all other versions. So what is an app developer to do?
UBOS and NVM
The Node Version Manager (NVM) was created to solve a variant of this problem,
but not this problem exactly: by manipulating the user’s $PATH
and a user-specific
configuration file (by default, ~/.nvm
), nvm
enables the user to use a
Node.js version of their choosing during development.
That’s great, but it is not so obvious how to use NVM for production deployments in which multiple Node apps from multiple vendors, using different Node.js versions have to coexist on the same device, running as system services, rather than something individual users run from the home directories.
So UBOS defines some additional conventions. Some apply at package build time, and some at package runtime (i.e. on the user’s Device).
At build time
Apps that depend on a particular Node.js version should:
-
declare a build dependency (
makedepends
) on NVM (packagenvm
). -
in the
prepare
section of theirPKGBUILD
, locally install the Node.js version they require, with the defaults for the current user. For example:nvm install 8.12.0
. -
build the package as intended, bundling any dependent modules as part of their own package. In other words, do not refer to Node.js modules outside of what is part of the installation of this version by
nvm
and the app itself. -
bundle the particular Node.js version as part of their own app package.
At run time
Apps that depend on a particular Node.js version should:
- run the Node.js version that they bundled as part of their own package.
Example
To see how this works in practice, consider the Mastodon package for UBOS at gitlab.com/ubos/ubos-mastodon.
In its PKGBUILD
file, the prepare()
function installs the needed Node.js
version into a local directory, using nvm
, like this:
NVM_DIR=$(pwd)/nvm nvm install ${NODE_VERSION}
where NODE_VERSION
is previously defined in this file. Then, during
package()
, this version of Node.js gets packaged with the app as part
of this command:
cp -a ${srcdir}/${pkgname}-${pkgver}/* ${pkgdir}/ubos/share/${pkgname}/mastodon/
And finally, the Systemd daemon invocation runs the bundled version of Node.js (see
file systemd/mastodon-streaming@.service
):
ExecStart=/ubos/share/mastodon/mastodon/nvm/versions/node/v8.15.1/bin/node /usr/bin/npm --scripts-prepend-node-path=auto run start