pyenv
and nvm
comes to mind. You can use zsh autoloads
to fix this, to “lazy load” shell scripts that need to be initialized when your shell is loaded.
This will prevent you from incurring the load on every spawned shell, postponing it to when you actually call the command you wish to load.
The following shows how you can do this for pyenv
.
In ~/.zshrc
add the following, that adds a folder $HOME/.zsh/autoloads/
to the zsh path, so it will find the autoload functions. Then register an autoload for each of the files in the folder by calling the autoload
built-in with the name of the function.
# register autoloads
fpath=($HOME/.zsh/autoloads $fpath)
for f in $(ls $HOME/.zsh/autoloads); do
autoload $f
done
I usually call the autoload functions the same as the scripts they intend to load. This causes trouble, however, because by default, it will load your script every time the autoloaded function is run. To prevent this, you can make use of the aptly named zsh function unfunction
- to remove the autoloaded function that will initialize your script once the autoloaded function has run the first time.
Over in ~/.zsh/autoloads/
, create a file to autoload pyenv
if [[ -z "$PYENV_SHELL" ]]; then
unfunction pyenv
echo "initializing pyenv" # remove this in the actual autoload
eval "$(pyenv init -)"
command pyenv "$@"
fi
It checks for some condition, that running eval $(pyenv init -)
will make come true. You should adjust this depending on a condition that will determine if your script is already initialized. In this case, if $PYENV_SHELL
is not set, it means pyenv
was not yet initialized, so we need to load it. First, call unfunction pyenv
, to undefine the very function (the autoload) that is being run. Then run the pyenv
-initializing code. This in effect replaces the pyenv
autoload command with the actual pyenv
, such that the next time pyenv
is run, the current fcuntion will not run, but the actual pyenv
command will.
To also make the actual pyenv
command work the first time around, when the autoloaded function runs, make sure to run it after the script has been initialized. This can be done with something like command pyenv "$@"
, which will forward all args given to the actual pyenv
command.
❯ pyenv local 3.8.14
initializing pyenv
❯ python --version
Python 3.8.14
The next time you call pyenv
, the actual command will be available instantly.
❯ pyenv local 3.8.14
❯ python --version
Python 3.8.14
I do this for a lot of commands . Actually, I stuck all my custom shell functions in there as well. Don’t know if that’s a good idea, but it seems to work fine.
Near instant shell load times! 🚀