lukechilds / zsh-nvm

Zsh plugin for installing, updating and loading nvm

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Call the lazy load function inside a script

ahmedelgabri opened this issue · comments

So, I have a couple of npm executables that are being used by my editor for linting & stuff. I'm trying to make this as dynamic as possible instead of me doing something like nvm use default before I open my editor, which most of the time I forget.

Also, these executables need to work from the local node_modules folder if exists otherwise fallback to the global one if available. So I'm trying to achieve this with the following bin scripts.

For eslint for example.

#!/usr/bin/env bash
$(npm-which eslint) $@

and the npm-which script looks like this

#!/usr/bin/env zsh

local npm_bin=$(npm bin) # <--- this is the problem
local bin_name=$1
local local_path="${npm_bin}/${bin_name}"

[[ -f $local_path ]] && echo $local_path && return
echo $(which $bin_name)

The problem is in the call to $(npm bin) this returns /usr/local/bin/npm & not the lazy loaded npm which is /Users/ahmed/.nvm/versions/node/v8.0.0/bin/npm

EDIT: So I removed that old npm install, but now the script returns an error instead

λ npm-which
npm not found
/Users/ahmed/.dotfiles/bin/npm-which:4: command not found: npm

So how can I make this work?

Hmmnn, the lazy loaders are shell functions that load the full nvm environment and then pass on the arguments to the correct command.

Your use case doesn't work because in zsh you can't export a shell function. So the subshell your script is running in doesn't have access to the lazy loader functions.

The only two solutions here are either fully load nvm before you run your script, or load nvm inside your script.

So which one do you think it's better?

I already tried source ~/.nvm/nvm.sh in the script & that worked fine but I'd like to just do this call once the first time it's needed & not on every call to the script.

If you do it inside the script you have to do it every time. The nvm environment is setup in the subshell and lost when the subshell has finished executing.

If you do it before the script you only have to do it once. nvm works by adding the selected node version path to your PATH variable which will be exported to subshells and therefore automatically be checked for a node executable.

Also, do you open your editor from the command line or via your desktop UI? Because running nvm use default before opening your editor will only work if you open it from the command line.

This is really a problem that would ideally be handled by the editor plugin though.

Wait, are you running these scripts from the command line?

Or is the idea that if you add these npm bin scripts your editor should use them over what it normally would?

Or is the idea that if you add these npm bin scripts your editor should use them over what it normally would?

This is the idea yes, but also if it can work both ways. In editors & CLI I won't say no :) I'm mainly using neovim but would like to be able to use this with any editor if possible too.

Ah ok, it can't really work both ways because nvm is for managing node versions inside your shell. So anything running outside the context of your shell doesn't really have any concept of what nvm or it's installed node versions are.

If you load a version of node inside your shell with nvm then it's gonna setup your PATH. So if you then load a text editor from that shell session then it'll have whichever version of node you loaded available in your PATH. That's really all you can do.

You could write a function called vim which first loads nvm and then loads vim to streamline this a bit.

Yeah I realized this too, the main downside of the vim function is that it will slow the startup of vim considerably. I'll try & see anyway.

Thanks for the help!

I have the exact same problem. I'm wondering about one possibility: what if we cached the $PATH that NVM sets when loaded? This would be practically free. Here's the scenario:

You open a fresh terminal. The zsh-nvm plugin is set to lazy load NVM, but at some (currently undetermined) point in time, it figured out that when NVM is loaded, it includes /home/max/.nvm/versions/node/v10.13.0/bin: to $PATH, for example. So it goes ahead and adds it to the $PATH which in turn allows all globally installed NPM modules as well as the default node to be accessed when the terminal was freshly opened. Then when the user next executes nvm or similar, it gets lazy loaded, and the $PATH is overwritten.

While this is somewhat complicated, I feel the gains are huge.