Using nvm in a makefile to switch node environment - node.js

I am trying to use Makefile to build Node projects. As a first step, I want to set node version using NVM. I tried the following code for that:
.PHONY: viz-ui
viz-ui:
. ${HOME}/.nvm/nvm.sh && nvm use 14.17.0
node -v
I set nvm use 16 before running make to test the output. After running make viz-ui, I get the following output:
. /home/vijayth2/.nvm/nvm.sh && nvm use 14.17.0
Now using node v14.17.0 (npm v6.14.13)
node -v
v16.14.2
In short, the node switch to 14.17.0 is not reflecting in the makefile, how can i fix it? Or what is the gap in my understanding of this?

Every line of a recipe is run in a brand-new shell. Therefore, when you reach node -v line, it is executed in a new shell that knows nothing about previous one that has set up different node version (this was executed in a separate shell and long gone).
You have basically two options:
Rewrite the recipe so that it all runs in a single shell invocation, e.g.:
.PHONY: viz-ui
viz-ui:
. ${HOME}/.nvm/nvm.sh && nvm use 14.17.0; \
node -v
or
Make use of .ONESHELL directive, so that all the recipe is executed in a single shell.

Related

Set node version for a single command using nvm

I have a command that must be run with Node 16 installed, no other version. However, I need to have the latest version of Node installed for regular use.
How can I configure things, perhaps with environment variables, so that just that one command uses Node 16?
Something like nvm use 16 && node -v && nvm use 19 is too slow, but aliasing in .zshrc is an option.
What I've done in one of my Projects is this:
I've switched to node 16: nvm use 16.
After that which node showed this path: /root/.nvm/versions/node/v16.19.0/bin/node
So I've simply created a symlink for this executable: ln -s $(which node) /usr/bin/node16
Finally I switched back the version: nvm use system
Now you can use your default node Version with node and the desired node-version for this command with node16.

Automatically use the right version of Node for a package

I know it is possible to switch between different versions of Node using NVM, n, or similar.
Is there a convenient way for the right version of Node to automatically be used when running commands within a given package? ("Right version" being determined by the engine tag or similar).
For instance, I would like to be able to do this:
cd mypackage-that-needs-node10
npm run serve
# ... node 10 is used
cd ..
cd mypackage-that-needs-node14
npm run serve
# ... node 14 is used
n supports an engine label to find Node.js version from package.json, and auto which includes more sources such as a .node-version file.
https://github.com/tj/n#specifying-nodejs-versions
For example:
$ n install engine
# or run the target version of node
$ n run auto index.js
# or execute a command with that Node.js in path
$ n exec auto npm run serve
A possible approach is to install node itself into your package, and have npm run scripts use it in preference to the system version of node. See node

npx runs a node version which does not exist on my machine

I tried to run this command npx create-react-app my-app and got this error
error #typescript-eslint/eslint-plugin#4.5.0: The engine "node" is incompatible with this module. Expected version "^10.12.0 || >=12.0.0". Got "11.13.0"
error Found incompatible module.
The weird thing is I used node version 15.0.1 (latest) and yarn version 1.22.10 (latest) and the version that npx used Got "11.13.0" which does not exist on my machine.
Anybody face this problem ? Please help, many thanks in advance.
The situation may be different on Windows, but on UNIX-like operating systems (including macOS), you can find the path to the node being executed by npx with:
/usr/bin/env node -p process.execPath
This is because the npx file starts with #!/usr/bin/env node. So you can use /usr/bin/env node to execute the same node that npx will.
-p means "print the value" and process.execPath is the path to the executable.
Why do you want to do the above and not just use which node?
which will report aliases, which means that it will report the node executable you will see in your shell. That's not what npx will use, and that seems a likely possibility to explain why npx might use a different Node.js version than you expect.
$ alias node=echo
$ node foo
foo
$ which node
node: aliased to echo
$ /usr/bin/env node -p process.execPath
/Users/trott/.nvm/versions/node/v15.0.1/bin/node
$

Updating to a particular version of node: paths being strange?

I'm trying to update node (on Ubuntu) and have been using the n package to do this.
I've run the following:
$ sudo npm install -g n
% sudo n 0.10.21
This appeared to run OK, but now I get the following:
$ which node
/usr/local/bin/node
$ node -v
0.6.4
$ /usr/local/bin/node -v
0.10.4
which is baffling to me.
How can I get rid of 0.6.4 and ensure that 0.10.4 is what runs when I type node?
This is actually a shell issue. I've only seen it in bash, but here goes:
Bash caches where it has found commands in the past. This means that if you place an executable (with the same name as something you've run before) earlier in the PATH, which will correctly find the new one, but bash will hit the cache and run the old one.
The easiest fix is simply to close your shell and open a new one. However, you can aldo use the command hash -d node to clear node from the cache (or type node to see whether it is in the cache and what it is pointing to).

Problem with making Capistrano run the shell tasks (nodejs deploying)

I am using capistrano to deploy a node.js application, and have a
problem with setting the shell tasks.
For instance, thought I have npm installed this fails:
run "npm install"
npm not found
and when I use
run "/opt/nvm/'cat /opt/nvm/alias/default'/bin/npm install"
the error is node not found
The deploy is managed by a special user for deploy.
Could you please tell what might cause this problem and how to solve it?
Using NVM and Capistrano is working for me by running the command through bash and sourcing the nvm.sh file first.
My NVM is installed in /opt/nvm, so the npm install task could look something like this:
namespace :npm do
desc 'Install the current npm environment.'
task :install do
invoke_command "bash -c '. /opt/nvm/nvm.sh && cd #{current_path} && npm install'", :via => run_method
end
end
So no need of manually setting the path to the binaries by reading the alias file from NVM.
Sounds like the npm/node executables are not on the $PATH for the remote user that is executing the Capistrano script.
You should double check which user Capistrano is running as and what the $PATH is (and correcting as required)
I ended up adding this to my Capfile
set :default_environment, {
'PATH' => "$PATH:/usr/local/ruby/bin/:/home/ubuntu/.nvm/v0.10.21/bin"
}
In the meantime (more than a year back tho) I've created a Capistrano extension for easy nvm usage: https://github.com/koenpunt/capistrano-nvm
The extension will map node and npm by default, but you can add any executable that needs nvm to run to it (eg. grunt).
A basic setup would work by adding the following to your deploy.rb:
require 'capistrano/nvm'
set :nvm_type, :user # or :system, depends on your nvm setup
set :nvm_node, 'v0.10.21'
set :nvm_map_bins, %w{node npm}
I was able to affect node version changes by adding lines like the following to my capistrano deploy scripts:
execute :'. ~/.nvm/nvm.sh && nvm use vOLDER_VERSION && nvm alias default vOLDER_VERSION'
execute :npm, 'install', '--silent --no-progress'
execute :npm, 'run', 'build'
execute :'. ~/.nvm/nvm.sh && nvm use stable && nvm alias default stable'
Where vOLDER_VERSION is the version of choice.
The way this works is it sources nvm, sets it to use the specified version, and sets that version as default. It then reverts those changes after the npm steps have been run. This way other parts of the deploy or other deploys still get to use the latest version.
If you don't care about other deploys you could just run that step once for your deployer user:
su deployerUser
nvm use vOLDER_VERSION
nvm alias default vOLDER_VERSION

Resources