Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NVM getting very slow on startup in Bash #1277

Closed
andyhennie opened this issue Oct 29, 2016 · 197 comments · Fixed by #2317
Closed

NVM getting very slow on startup in Bash #1277

andyhennie opened this issue Oct 29, 2016 · 197 comments · Fixed by #2317
Labels
needs followup We need some info or action from whoever filed this issue/PR. performance This relates to anything regarding the speed of using nvm.

Comments

@andyhennie
Copy link

I love NVM, but I've noticed that NVM is getting really slow during startup. See attached screenshot for what I mean: http://take.ms/LPOv3

Is this a bug or is something wrong on my Mac?

@ljharb
Copy link
Member

ljharb commented Oct 29, 2016

What's nvm ls and nvm debug print out?

@ljharb
Copy link
Member

ljharb commented Oct 29, 2016

You can also try adding --no-use to the end of the second nvm line (the one doing the sourcing) to confirm that it's the auto-use code path that's being slow.

@ljharb ljharb added needs followup We need some info or action from whoever filed this issue/PR. performance This relates to anything regarding the speed of using nvm. labels Oct 29, 2016
@andyhennie
Copy link
Author

@ljharb
Adding --no-use makes it superfast, but then it doesnt load node. But I guess it confirms that the auto-use code path is slow. Here are the nvm ls and nvm debug

nvm ls
->       v6.9.1
default -> 6.9.1 (-> v6.9.1)
node -> stable (-> v6.9.1) (default)
stable -> 6.9 (-> v6.9.1) (default)
iojs -> N/A (default)
lts/* -> lts/boron (-> v6.9.1)
lts/argon -> v4.6.1 (-> N/A)
lts/boron -> v6.9.1
nvm debug
nvm --version: v0.32.1
$SHELL: /bin/bash
$HOME: /Users/Andreas
$NVM_DIR: '$HOME/.nvm'
$PREFIX: ''
$NPM_CONFIG_PREFIX: ''
nvm current: v6.9.1
which node: $NVM_DIR/versions/node/v6.9.1/bin/node
which iojs:
which npm: $NVM_DIR/versions/node/v6.9.1/bin/npm
npm config get prefix: $NVM_DIR/versions/node/v6.9.1
npm root -g: $NVM_DIR/versions/node/v6.9.1/lib/node_modules

@ljharb
Copy link
Member

ljharb commented Oct 31, 2016

Do you have a .nvmrc file anywhere, like ~/.nvmrc?

@andyhennie
Copy link
Author

andyhennie commented Oct 31, 2016

@ljharb the one line I have in that file is
onload-script=npm-autoinit/autoinit

Tried to remove it, didn't make any difference, so added it back.

@ljharb
Copy link
Member

ljharb commented Nov 1, 2016

@ahennie in a file called nVmrc, you have that line?

Can you provide a little more info on your Mac? Do you have an SSD, how old is it, how fast/much RAM, etc?

@mitermayer
Copy link

This is also very slow for me on gentoo linux.

@ljharb
Copy link
Member

ljharb commented Nov 2, 2016

@mitermayer can you also go through the same steps above and see if you get the same or different results?

@andyhennie
Copy link
Author

@ljharb Sorry, that was .nPmrc. I don't have a .nVmrc-file. It must be sw, not hw related. I got Macbook Pro 15" i7, 16gb RAM, SSD. What could it be?

@ljharb
Copy link
Member

ljharb commented Nov 3, 2016

@ahennie that should be fast enough. Basically it's that nvm use calls into npm config get prefix, which is very slow. I'll keep looking into it.

@andyhennie
Copy link
Author

@ljharb thanks. it wasnt slow like this earlier. does the number of global modules affect the speed? other things I can do to speed it up?

@ljharb
Copy link
Member

ljharb commented Nov 4, 2016

When you say "earlier" do you mean on an earlier version, before I was doing prefix checking? Or do you mean on the same version of nvm?

@carlosjs23
Copy link

same issue too.

@andyhennie
Copy link
Author

@ljharb it's hard to say. I installed nvm months ago, but never really used node. However loading the bash has always been fast. I have been coding node a lot more lately, including installing a few global modules, and it suddenly have gotten slower. I also updated to the newest version of nvm, npm and node. Deleted a few global modules now, but it's still slow. So I think the slowness was intruduced in any of the updates.

@ljharb
Copy link
Member

ljharb commented Nov 7, 2016

It's likely the npm config get prefix call then.

@andyhennie
Copy link
Author

@ljharb suddenly it's faster again. don't know why. but I thought you should know, before you spend to much time on it.

@ryankask
Copy link

I just checked out the latest tag and noticed this. I forget what tag I was previously using but it was in the v0.31 series.

Adding the the --no-use fixes the issue.

@Nick011
Copy link

Nick011 commented Nov 23, 2016

Experiencing the same problem. Everything was fine until I upgraded OSX to Sierra a few days ago. Ran brew update and brew upgrade, but it's still slow. --no-use Makes it better, but still slightly slower than what it was before I upgraded.

When I run nvm ls It takes about 2-3 seconds to start, then lists everything down to system then takes 2-3 seconds for every alias after that. Here is my output:

➜  ~ nvm ls
        v5.10.1
         v6.1.0
         v6.6.0
->       v6.9.1
         system
default -> v6.9.1
node -> stable (-> v6.9.1)
stable -> 6.9 (-> v6.9.1) (default)
iojs -> iojs- (-> system) (default)
lts/* -> lts/boron (-> v6.9.1)
lts/argon -> v4.6.2 (-> N/A)
lts/boron -> v6.9.1

I'm running a 2013 15in macbook pro. 2.7Ghz, 16GB RAM.
I'm using iterm2 and oh-my-zsh, but saw someone else here had the same problem with bash.

@ljharb
Copy link
Member

ljharb commented Nov 24, 2016

@Nick011 nvm is not supported via homebrew (the homebrew formula says this when you install it). If you brew uninstall nvm, and then install it properly via the curl script in the readme, my suspicion is that it will go much faster.

@nico1510
Copy link

same issue here... --no-use fixes it but also fails to load node

@ljharb
Copy link
Member

ljharb commented Nov 25, 2016

@nico1510 right, the npm config get prefix call that nvm is making when running nvm use is the slowest part. I don't yet have a solution to speed that up.

@martinheidegger
Copy link

To investigate the performance issues myself, I tried to setup some performance logging in a forked branch:
https://github.com/martinheidegger/nvm/tree/debug/performance

and I also come to the conclusion that the biggest issue is starting node. (npm config get prefix is a node script, as opposed to all the other scripts).

@ljharb
Copy link
Member

ljharb commented Dec 6, 2016

@martinheidegger i think you're spot on. If anyone can come up with a way to perfectly emulate npm config get prefix without invoking node (especially if it can be PRred into npm itself so that they'll keep it up to date), that would likely erase most people's performance issues.

@martinheidegger
Copy link

martinheidegger commented Dec 6, 2016

@ljharb I ran another test for the performance of npm config get prefix and it seems to have not changed much over the versions: https://gist.github.com/martinheidegger/32d00e90e0163a22a4ffc78df796001e

I opened npm/npm#15149 added comments to npm/npm#14458 (comment) in order to let the npm team know of this problem as well (with some extended info).

@martinheidegger
Copy link

I opened nodejs/help#396 in order to figure out if Node.js and NPM could share the same logic in order for nvm to not need to rely on Node and/or make NPM faster.

Quoting:

If npm wanted to use that, they should file an issue or pull request to make it public API.

I guess same can be said of nvm?

eudika added a commit to eudika/prezto that referenced this issue Aug 28, 2020
$NVM_DIR/nvm.sh is a slow script and has doubled time to load zsh.
In this commit, the script is not loaded until required.
cf. nvm-sh/nvm#1277
eudika added a commit to eudika/prezto that referenced this issue Aug 30, 2020
$NVM_DIR/nvm.sh is a slow script and has doubled time to load zsh.
In this commit, the script is not loaded until required.
cf. nvm-sh/nvm#1277
@king-11
Copy link

king-11 commented Sep 16, 2020

this code snippet has really used my startup time while ensuring that I also have access to global packages as well as yarn globals and yarn project have same node env version.

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

NODE_GLOBALS=(`find ~/.nvm/versions/node -maxdepth 3 -type l -wholename '*/bin/*' | xargs -n1 basename | sort | uniq`)
NODE_GLOBALS+=(node nvm yarn)

_load_nvm() {
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion
}

for cmd in "${NODE_GLOBALS[@]}"; do
eval "function ${cmd}(){ unset -f ${NODE_GLOBALS[*]}; _load_nvm; unset -f _load_nvm; ${cmd} \$@; }"
done
unset cmd NODE_GLOBALS

export PATH="$PATH:$HOME/.yarn/bin"```

@milahu

This comment has been minimized.

@ljharb

This comment has been minimized.

@milahu

This comment has been minimized.

@ljharb

This comment has been minimized.

@milahu

This comment has been minimized.

@ljharb

This comment has been minimized.

@milahu

This comment has been minimized.

@ljharb
Copy link
Member

ljharb commented Oct 8, 2020

For future reference, nvm supports mostly POSIX shells - ksh, dash, sh, bash, zsh in particular.

@tilsmen
Copy link

tilsmen commented Oct 8, 2020

@milahu This was implemented long time ago already, together with other improvements. However it never got merged due to reasons you can read yourself, thought it might be worth mentioning. There is a hard fork which is fast and also does this caching. Here is the reasoning and the hard fork, I am using that one for very long time and didn't had any problems with it wzrdtales/nvm-ng#2

Don't forget the --fast-reuse flag to activate this fast path.

@milahu

This comment has been minimized.

@ljharb

This comment has been minimized.

@ljharb
Copy link
Member

ljharb commented Oct 8, 2020

@tilsmen Careful using any forks; that one's missing over 2 years of improvements.

@tilsmen
Copy link

tilsmen commented Oct 9, 2020

yes i know @ljharb but nothing really meaningful was added (for my terms, not in general don't get me wrong not trying to offend here) during this 2 years. The difference of the hard fork and your original are just two commits in the hard fork which are like a show stopper to me from your work. Everything is working with this fork also with the newest node version without any flaw and I have the benefit of not being disturbed in my workflow and still able to use my console normal. So I think it is reasonable, if you by any chance improve here the loading times let me know though.

@ljharb
Copy link
Member

ljharb commented Oct 9, 2020

@tilsmen luckily i'm very close to releasing a performance improvement here - i've just opened #2317. if you could try that out locally and comment on the PR with performance comparisons, that would be very helpful.

@revolter

This comment has been minimized.

@bogdanu

This comment was marked as outdated.

@ljharb

This comment was marked as resolved.

@bogdanu
Copy link

bogdanu commented Jun 24, 2022

@bogdanu thats not good advice, because then you’re not handling npm, npx, corepack, and any other binaries the default version of node might bring with it.

Well, you can create a few aliases for the tools that you use, the advantage is that when I open my shell for random things outside Node ecosystem it's fast, and when I use node/npm/whatever I can pay the penalty.

To lazy load multiple aliases:

export NVM_DIR="$HOME/.nvm"
init-nvm() {
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion
}
create_lazy_alias() {
for A in $@; do
alias $A="which node || { init-nvm && unalias $*; } && $A \"\$@\""
done
}
create_lazy_alias node npm npx yarn corepack

@laur89
Copy link

laur89 commented Jun 24, 2022

This alias method has been discussed extensively on this gist; I myself am using this version (with bash)
For completeness, here it is:

export NVM_DIR="$HOME/.nvm"
mapfile -t __NODE_GLOBALS < <(find "$NVM_DIR/versions/node/"*/bin/ -maxdepth 1 -mindepth 1 -type l -print0 | xargs --null -n1 basename | sort --unique)
__NODE_GLOBALS+=(node nvm yarn)

# instead of using --no-use flag, load nvm lazily:
_load_nvm() {
    [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
    [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion
}

for cmd in "${__NODE_GLOBALS[@]}"; do
    eval "function ${cmd}(){ unset -f ${__NODE_GLOBALS[*]}; _load_nvm; unset -f _load_nvm; ${cmd} \"\$@\"; }"
done
unset cmd __NODE_GLOBALS

With this solution, prior to launching node or any other node-based binaries, your shell has following wrappers:

$ type npx
npx is a function
npx () 
{ 
    unset -f corepack fast npm npx node nvm yarn;
    _load_nvm;
    unset -f _load_nvm;
    npx "$@"
}

@CervEdin

This comment was marked as duplicate.

@danielzen
Copy link

If you are looking for a lazy load for zsh:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs followup We need some info or action from whoever filed this issue/PR. performance This relates to anything regarding the speed of using nvm.
Projects
None yet
Development

Successfully merging a pull request may close this issue.