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

Lazy load nvm #1186

Closed

Conversation

rtfpessoa
Copy link

nvm takes on average half of a second to load, which is more than whole prezto takes to load.

This can be noticed when you open a new shell.

To avoid this, we are creating placeholder function for nvm, node, and all the node packages previously installed in the system to only load nvm when it is needed.

This code is based on the scripts:

nvm takes on average half of a second to load,
which is more than whole prezto takes to load.
This can be noticed when you open a new shell.
To avoid this, we are creating placeholder function for nvm, node,
and all the node packages previously installed in the system to only
load nvm when it is needed.

This code is based on the scripts:
* https://www.reddit.com/r/node/comments/4tg5jg/lazy_load_nvm_for_faster_shell_start/d5ib9fs
* http://broken-by.me/lazy-load-nvm/
* nvm-sh/nvm#781 (comment)
@rtfpessoa rtfpessoa mentioned this pull request Aug 26, 2016

for cmd in "${NODE_GLOBALS[@]}"; do
# Skip defining the function if the binary is already in the PATH
if ! which ${cmd} &>/dev/null; then
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, I was wondering how you were going to handle package binaries like https://www.npmjs.com/package/which

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am also trying #1178. Nodenv seems much faster on init and uses a different method for managing different node versions.

Since I already use rbenv which is much better than rvm and nodenv is a fork. I decided to give it a try.

Seems good.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've had great success with nodenv and started using it because I was also familiar with rbenv. I too tried nvm and also found it noticeably slowed down my shell.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could probably be improved by using $+commands[$cmd].

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me know if you want any change I can update

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Depending on what you're trying to do, is-callable from the helper module or $+commands would be preferable.

@joaosa
Copy link

joaosa commented Sep 25, 2016

@sorin-ionescu Any chance this could get merged? :)

before:

/usr/bin/time zsh -i -c exit
2.75 real         1.20 user         1.00 sys

after:

/usr/bin/time zsh -i -c exit
0.63 real         0.25 user         0.38 sys

@ascandella
Copy link

I also run a custom fork solely so I can include this patch.

facastagnini added a commit to prezto-inactive-community-fork/prezto that referenced this pull request Dec 29, 2016
@facastagnini
Copy link
Collaborator

This PR got merged in the community maintained fork of this repo.

zsh-users is an organization dedicated to host Zsh community projects and therefore became the rational home for a community maintained version of prezto.

Your contribution is greatly appreciated!

https://github.com/zsh-users/prezto

Copy link
Collaborator

@belak belak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a few tweaks I'd like to see, but the general concept looks good.

NVM_DIR=$1
# Skip adding binaries if there is no node version installed yet
if [ -d $NVM_DIR/versions/node ]; then
NODE_GLOBALS=(`find $NVM_DIR/versions/node -maxdepth 3 \( -type l -o -type f \) -wholename '*/bin/*' | xargs -n1 basename | sort | uniq`)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be willing to bet that this doesn't work in either osx or linux. There should be a way to use extended glob syntax to do something like this but only use zsh internals.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would be the part not working in OSX or Linux?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After looking a bit closer, it looks fine. I've just run into strange issues with find on linux and osx being incompatible.

for cmd in "${NODE_GLOBALS[@]}"; do
# Skip defining the function if the binary is already in the PATH
if ! which ${cmd} &>/dev/null; then
eval "${cmd}() { unset -f ${cmd} &>/dev/null; [ -z \${NVM_LOADED+x} ] && load_nvm; ${cmd} \$@; }"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unsetting this specific command and using NVM_LOADED shouldn't be needed because we unset all the functions in load_nvm anyway, so we don't need to track it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additionally, because this is using eval, I'd feel a lot better if there was a way to know that the command names were sanitized.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any suggestions?

@ericbn
Copy link

ericbn commented May 20, 2017

Replaced nvm by nodenv and my startup time when from 2s to 0.2s. Why bother about nvm?

@belak
Copy link
Collaborator

belak commented Jun 19, 2017

What's the status on this? It doesn't look like there's been an update by the author more than a month after changes were requested. Does anyone else want to take this up?

@rtfpessoa
Copy link
Author

I completely missed this @belak.

It will probably take me some days to update this. If you want to do it I added permissions for the owners to edit this pr.

@belak
Copy link
Collaborator

belak commented Jun 19, 2017

No worries. Thanks for the response! I don't know if I'll get to it soon either, so no rush. Just trying to follow up on a few loose ends. :)

@jeffwidman
Copy link
Collaborator

jeffwidman commented Oct 4, 2017

I'm hesitant about this, and I'm hoping @creationix would be willing to take a look before we merge this.

I used to follow the nvm repo for a while, and there were often users complaining about speed, but every time they suggested a "fix" @creationix pointed out problems with their solution. For example, the OP cites as inspiration nvm-sh/nvm#781 (comment) but the very next comment is from the maintainer saying that that is a flawed approach.

That said, I don't work on any node projects right now, so haven't stayed up to date with nvm, so perhaps this implementation works fine, I just don't know and given the context I'd rather be cautious.

@creationix
Copy link

creationix commented Oct 4, 2017

There has been quite a bit of feature and code growth since I handed nvm over to a new maintainer. If you look at the contribution graph my initial implementation is a fraction of the overall code.

screen shot 2017-10-04 at 1 47 16 pm

If I were to write nvm again knowing what I now know, it would look a lot like nvs. https://github.com/jasongin/nvs

There is no need to have all the heavy logic in shell. The only thing that has to be shell script is changing the current PATH value. Everything else can be done in a sub-process on-demand.

@creationix
Copy link

I'm afraid I don't know enough about the current nvm implementation to give good feedback on your lazy load approach. Good luck!

@jeffwidman
Copy link
Collaborator

Thanks for weighing in @creationix! I actually meant to tag the new maintainer, as he is the one whose comments I've seen and didn't realize he wasn't you... so tag @ljharb 😄

@ljharb
Copy link

ljharb commented Oct 4, 2017

"code bloat" is pretty uncharitable; there's quite a lot of refactors, bug fixes, and POSIX robustness improvements in there :-)

Lazy loading nvm is imo not a good idea; it will either come with caveats, or break encapsulation by replicating the implementation.

The only reason it's slow is because npm config get prefix is slow, and people who have a "prefix" set with nvm run into very surprising and silent breakages, so it's worth the cost for the people who don't have a "prefix" set.

I'd be willing to bet that if you temporarily overwrote the $PATH with an npm that returned the expected value for npm config get prefix, then sourced nvm.sh greedily, and then removed your modification from $PATH, that it would be sufficiently fast that you wouldn't need to lazy load it at all.

@creationix
Copy link

@ljharb

"code bloat" is pretty uncharitable

Sorry, sometimes I forget the negative connotations with that phrase. You've done great work!

@jeffwidman
Copy link
Collaborator

Thanks for chiming in @ljharb, much appreciated

@rtfpessoa rtfpessoa closed this Mar 10, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet