Vscode: VS Code with NVM

Created on 9 Jan 2016  路  35Comments  路  Source: microsoft/vscode

Hi, thank you for great app.

So, I hope VS Code sets specified environment variables when it starts.
I use a NodeJS Version Manager such as nvm, then a path to NodeJS is not added to PATH until nvm do it. (Also NODE_PATH, NODE_HOME, etc.)
That is, CLI of modules such as Gulp, Grunt, UglifyJS, etc. are not work as Task of VS Code. (VS Code can't find out these.)

When I add to PATH a path to these CLIs such as /path/to/nvm/v4.2.4 and call code command, these Tasks work fine. Or when I add a following line to VS Code DIRECTORY/bin/code.js.

process.env['PATH'] += require('path').delimiter + '/path/to/nvm/v4.2.4';

But, When VS Code is started from launcher such as Windows Start Menu, these are not work because Code.exe is called directly.

As everyone knows, NodeJS is updated frequently. A better solution I think is that VS Code sets environment variables written in settings.json that was specified by user. Or user is given a chance such as "Startup Script(or Command)" to do something.

bug verified

Most helpful comment

The above approach (nvm use then launch code) worked nicely for me too.

I've also being specifying the node executable too for the times that I forget to launch code via a terminal. For example:

        {
            "type": "node",
            "request": "launch",
            "name": "generator scribble",
            "runtimeExecutable": "${env:HOME}/.nvm/versions/node/v4.6.1/bin/node",
            "program": "${workspaceRoot}/generators/index.js"
        }

All 35 comments

This should only happen on Windows. Other OSs work properly.

This issue occurred in Ubuntu also.
I think that it occurs regardless of which OS.
Paths to node and CLI commands such as gulp are not added to PATH until nvm do it. VS Code can't find out these.

Code does find these in Linux and OS X. Please try it one more time in Linux and confirm that it doesn't work. If that's the case, it's a separate issue.

Yes, I confirmed it again, and I got same result.
For example, I did Tasks: Run Task, and VS Code said "Gulp is not installed on your system".
Of course Gulp is already installed.

I think that getUserEnvironment() makes the process take over environment variables from parent process.
But path to Gulp is not added to PATH yet. VS Code can't find out these because PATH does not include Gulp.
The cause of this issue is unrelated to getUserEnvironment(). The cause is that necessary paths are not added to PATH when VS Code starts.

getUserEnvironment() exists for the specific purpose that Code cannot rely on inheriting the environment from its parent process. It spawns a shell and reads the environment from it.

In Linux, what do you get when you run $SHELL -ilc env? This should print out the correct PATH, one that points to gulp.

Ok, I checked PATH again:

starman@blue3:~$ $SHELL -ilc env
  :
  :
SHELL=/bin/bash
  :
  :
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
  :
  :
NVM_NODEJS_ORG_MIRROR=https://nodejs.org/dist
NVM_IOJS_ORG_MIRROR=https://iojs.org/dist
  :
  :
starman@blue3:~$ printenv PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
starman@blue3:~$ echo $0
/bin/bash

Of course PATH does not include a path to Gulp, as I said repeatedly. Because Node Version Manager such as nvm adds these paths to the PATH. It in Windows also do the same.

starman@blue3:~$ nvm use v4.2.1
Now using node v4.2.1 (npm v2.14.7)
starman@blue3:~$ gulp -v
[18:06:56] CLI version 3.9.0
starman@blue3:~$ printenv PATH
/home/starman/.nvm/versions/node/v4.2.1/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games

gulp -v above works correctly because the PATH includes /home/starman/.nvm/versions/node/v4.2.1/bin that includes gulp after nvm use.
We can avoid this issue temporarily in Windows rather than Linux, by using bin/code.js (in some cases).

So, the point of this issue is NOT that these paths are not already added to PATH, it is that we have no way to do it when VS Code starts. For example, VS Code sets environment variables a user specified when it starts, or it gives a chance such as "Startup Script(or Command)" to do something. (This Startup Script(or Command) makes nvm run, or it adds these paths to PATH.)
https://github.com/Microsoft/vscode/issues/1895#issue-125768845

Now here's what I don't understand. getUserEnvironment() was implemented to fix exactly this issue. By calling $SHELL -ilc env, it should've picked up .bash_profile or .bashrc which contains the call to nvm, which would set the variables correctly. I can confirm that works because I also use nvm every day on OS X. It works for me. And many others.

We just have to figure out what is different in your system that makes it not work. Where did nvm configure itself in your system? .bash_profile, .bashrc, some other config file?

Yes, .bashrc loads nvm in my system. And it seems that nvm.sh was done correctly.

I think that you might set nvm alias default before?, or you wrote .nvmrc?
That is, in your system, the paths were already added to PATH before you run nvm use, right? nvm use was already called automatically in some way.

Anyway, nvm default is not set in my system, and nvm use doesn't run automatically in my system. Also, some managers such as nvmw (for Windows) do not have an option that makes it run automatically, as default.

The paths may be already added to PATH when VS Code runs if a manager was called automatically in some way, otherwise these are not.

Maybe, does your system have a default node? (node that was installed without nvm)

I see. So, when you spawn a shell in your system you don't have a node in the PATH? You always need to run nvm use every time you want to use Node?

In some cases, Yes.
In a machine I everyday use, I configured the "auto-run" version manager. In others, for example, I was using nvmw before, but nvmw has some issues for me, then I removed the setting for auto-run. (nvmw doesn't support auto-run itself, then I used "startup" of Windows.) Also, In another machine (Ubuntu), I didn't configure auto-run because I used it to compile some versions of node.
Maybe I think that cases that the auto-run is not used are not uncommon, because this option of many managers is turned off as default. And node is updated frequently.

Got it. I argue your situation doesn't happen often. People usually either have node installed globally or just have a default node set up in nvm. I suggest you do the same.

An environment variable setup in settings.json wouldn't work for your, since you want to add to the PATH variable, not set it. A startup script could work, but you can always achieve that outside of vscode by doing nvm use 0.12 ; code.

Another alternative would be to use a specific node as the task command and point it to the gulp or grunt entrypoints inside the node_modules folder.

Ok.
I made a shell script that sets PATH and calls code, and I am using it instead of code.
I think that this is safety way to avoid using node of involuntary version.

So, my English is very poor. I couldn't explain well, but you interacted very patiently and kindly. Thank you :smiley:

Thanks for your ideas and feedback!

I'm still a little bit confused by the resolution here. Are you saying users that use nvm must launch VS Code via the terminal in order to have it use the nvm version of node? This is currently the way I have to launch VS Code on OSX to have it use the nvm version.

@vprasanth, no. @anseki seems to not have a default alias in nvm. You are maybe in the same position. You should run nvm alias default node to set up a default. It should work then.

Hi @vprasanth,
If you use a version manager that doesn't support default version such as Windows nvm, as you said, you must call nvm in a terminal before you start VS Code.
But if you use a version manager that supports default version, as @joaomoreno said, you can set default version to start VS Code without calling nvm. And I think that you use that on OSX.

@joaomoreno @anseki sweet thanks! I didn't even know I could do that. I was using nvm use xxxx within my bash_profile. Thanks!

@joaomoreno - It would be great if VS Code ran nvm use before running a node script. This allows each project to specify the version of node to use for that project, via a .nvmrc file.

What do you mean by _running a node script_? Where does this happen?

All of the tools, Gulp, Grunt, UglifyJS, mentioned by the OP in this issue are node.js scripts.
In particular when launching a task to run one of these tools, from VS Code, the editor must be running them via an instance of the node.js runtime.

Since there is now a range of node.js runtime versions available with breaking changes between them, different projects that I work on use different versions. NVM as a tool is great for selecting a version for a particular project, and with the .nvmrc file NVM can automatically set the necessary version by simply running nvm use (i.e. not specifying a version).

So for a concrete example, in the launch.json debug configuration file, I might have

  "configurations": [
    {
      "name": "Protractor",
      "type": "node",
      "request": "launch",
      "program": "${workspaceRoot}/node_modules/protractor/bin/protractor",
      "stopOnEntry": true,
      "args": ["protractor.conf.js"],
      "cwd": "${workspaceRoot}",
      "preLaunchTask": null,
      "runtimeExecutable": null,
      "runtimeArgs": [
        "--nolazy"
      ],
      "env": {
        "NODE_ENV": "development"
      },
      "console": "internalConsole",
      "sourceMaps": true,
      "outDir": null
    }
]

The protractor tool is a node.js script that will currently be run under the default installation of node.js on the system. But if this project requires a different version of node in order to run the protractor script it is stuffed.

Does that make sense?

Here's how you can do it, at least for debugging:

  1. Change runtimeExecutable in your debug configuration to ${workspaceRoot}/node.sh.
  2. Create a node.sh executable file at the root of your workspace with the following contents (adapt to your own shell):
#!/bin/zsh
source ~/.zshrc
nvm run $*

It isn't a great experience, but we don't want to hardcode the notion of nvm into Code. You could maybe convince the vscode-node-debug extension to do so, though.

@joaomoreno thanks for the workaround. I'll take a look at the node-debug extension people.

This issue also affects me. On Ubuntu 16.04 using nvm, I use a node module that checks for /usr/bin/env node, but that doesn't get called properly within VSC, though it works fine in terminal when I run which node since it is properly configured in my $PATH.

Would it be possible to add a custom path to VSC's user settings? We currently have:

"git.path": null,
"php.validate.executablePath": null,

Perhaps it would help to add a custom path for node that way it gets called properly.

Hi @theetrain,

For your information, this is my solution:
I use a shell script that sets environment and starts VS Code.
Since Node.js uses some variables other than PATH, it sets these also:

  • NODE_HOME : The path to directory that contains node
  • NODE_PATH : NPM global node_modules directory (e.g. npm root -g)

Or you could execute this before opening vs code
Eg:
nvm alias node v4.8.1
nvm alias node v6.10.1

The following worked for me too:

$ nvm use <node_version>
$ code

It would be nice if there is an easier way to switch node versions while you are in the IDE.

The workaround by @joaomoreno worked well for me. I was using bash instead of zsh so I posted the updated script and details over on my blog: NVM and VS Code for anyone who's interested.

After reading this, I got the impression that it would make sense to add "nvm" support to node-debug. So something like "nvm": "6.5".
I've created this feature request.

The above approach (nvm use then launch code) worked nicely for me too.

I've also being specifying the node executable too for the times that I forget to launch code via a terminal. For example:

        {
            "type": "node",
            "request": "launch",
            "name": "generator scribble",
            "runtimeExecutable": "${env:HOME}/.nvm/versions/node/v4.6.1/bin/node",
            "program": "${workspaceRoot}/generators/index.js"
        }

Thanks @biddster
"runtimeExecutable": "${env:HOME}/.nvm/versions/node/v4.6.1/bin/node", worked for me.

Thanks @biddster

I just went into my command line, did a which node to give me my nvm's node location and used that path. For now, I'm very happy.

(Sorry guys, pretty long discussion, maybe I missed the answer to my question)

My environment:

  • I have nvm installed (Arch Linux)
  • I have nvm sourced from .bashrc: source /usr/share/nvm/init-nvm.sh (.bash_profile sources .bashrc)
  • Node can be found in PATH
  • I configured its default: nvm alias default node
  • I do not have global node
  • Visual Studio Code 1.15.1

So when I run my Node.js project in debug mode in Visual Studio Code (Code was opened via icon) I get an error "Cannot find runtime 'node' on PATH. Make sure to have 'node' installed.". I checked process.env in developer tools and there is no nvm mention. While integrated terminal knows node command and has correct env. variables.

But when I run Code from terminal it works fine and process.env has all nvm related stuff.

Not sure if I should create a separate issue as there were many issues on this topic but I can not find a clear answer why Code running from GUI does not set nvm variables correctly.

Thank you.

Similar issues to @gg-berdzenishvili. I have Linux Mint 18.2 with bash. nvm is sourced in ~/.bashrc but when launching code from the menu or desktop, any extension that relies on node doesn't function correctly such as flow-for-vscode will show an error that node cannot be found in the path.

As others have said, I'm sure I could hack around and make a shell script to set the env variables and then launch code, but I feel this is something one would expect to work out of the box. With the large number of people using nvm to manage node installs, it may be worth it to better the support for nvm out of the box.

I found a way to use nvm-exec to override the default node.js version with the one specified in the project's .nvmrc: https://github.com/Microsoft/vscode/issues/16173#issuecomment-343223708

Was this page helpful?
0 / 5 - 0 ratings