Mon terminal et zsh sont long à démarrer (blame nvm)

Le terminal, c’est une sorte de couteau suisse pour les développeurs. Il permet de faire énormément de choses - presque tout d’ailleurs - et on s’en sert très souvent. Alors quand le temps de lancement du terminal s’allonge, je ne vous cache pas que c’est très embêtant.

C’était mon cas avec iTerm2 + oh-my-zsh, et on va voir comment trouver les problèmes à la source.

Identifier les causes

Je n’ai pas forcément fait attention au moment exact où mon terminal a commencé à être capricieux pour se lancer. J’ai l’impression que ça a commencé la semaine marquée par l’arrivée d’un nouveau super pouvoir du MDM sur nos machines pro. Il analysait toutes les commandes exécutées pour vérifier les bons privilèges à appliquer.

Une belle coïncidence, c’était le suspect parfait. Je l’ai un peu blâmé sans trop chercher plus loin. Et puis un jour, il est arrivé ce fameux imprévu qui permet au héros de se lancer dans l’aventure.

J’étais en pair avec un collègue pour l’aider sur une erreur autour de cocoapods et iOS. Je lui fais installer un version manager pour Ruby, on modifie son .zshrc, et on veut supprimer le Podfile.lock pour réinstaller proprement les packages. Mais dans la rapidité de l’action, il tape rm .zshrc. Aïe. Coup dur.

À ce moment-là, mon collègue est un peu dégoûté - je l’aurais été aussi. Avec rm, ça ne part pas à la corbeille, on ne récupère pas facilement ce que l’on a supprimé. Ça l’embête parce qu’il avait effectué plusieurs configurations dedans, et qu’il avait passé une heure avec la DSI pour optimiser le temps de chargement. Hop hop hop, attends. Quoi ?!

Lui aussi avait son terminal qui était long au lancement, et de mémoire, ça venait en partie de l’initialisation de nvm. Me voilà avec une piste intéressante. Je l’ai gardée dans un coin de tête, jusqu’à hier soir où j’ai fouillé les internets avec une idée de direction plus précise.

Mesurer le temps

À l’aide de deux instructions, on peut obtenir un rapport avec les différentes étapes exécutées au lancement de zsh et le temps associé.

Il suffit de modifier le fichier .zshrc pour y ajouter zmodload zsh/zprof au tout début, à la première ligne. On quitte le terminal, on le relance et on tape la commande zprof.

num  calls                time                       self            name
-----------------------------------------------------------------------------------
 1)    2        3047,39  1523,69   43,08%   2046,60  1023,30   28,93%  nvm
 2)    1        4998,69  4998,69   70,66%   1951,31  1951,31   27,58%  nvm_auto
 3)    1         821,18   821,18   11,61%    665,29   665,29    9,40%  nvm_ensure_version_installed
 4)    1         563,64   563,64    7,97%    563,64   563,64    7,97%  is_update_available
 5)    1         743,74   743,74   10,51%    180,11   180,11    2,55%  /.oh-my-zsh/tools/check_for_upgrade.sh
 6)    1         176,44   176,44    2,49%    174,59   174,59    2,47%  nvm_die_on_prefix
 7)    1         155,88   155,88    2,20%    155,88   155,88    2,20%  nvm_is_version_installed
 8)    1          93,04    93,04    1,32%     51,05    51,05    0,72%  compinit

Dans ce tableau, on retrouve le nom des étapes, le temps, le pourcentage du temps par rapport à l’ensemble, et c’est même classé dans l’ordre du plus long au plus rapide.

Sur ma machine, je vois clairement que nvm est dans le haut du panier. Plusieurs noms d’étapes semblent liées à nvm et elles prennent énormément de temps. Je vais donc optimiser le lancement de nvm, le reste me semble anecdotique. Je le ferais ou pas un jour. Sûrement jamais. :)

Améliorer l’initialisation de nvm

J’ai trouvé plusieurs moyens pour pallier la lenteur de nvm.

Supprimer nvm du .zshrc

Quand on installe nvm, il y a des instructions à ajouter dans notre configuration .zshrc. Leurs rôles sont de charger nvm, de s’assurer qu’il est à jour, de préparer l’auto-complétion, etc. C’est ce qui ralentit le lancement de notre terminal. Ces instructions ressemblent à ça :

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

Bon. Eh bien de manière pragmatique, on peut supprimer ces instructions de notre configuration .zshrc et le temps de lancement sera grandement amélioré. Si on n’utilise plus nvm, node et compagnie, ou très peu souvent, on n’a pas envie de pourrir l’expérience nominale de notre terminal.

Lazy loading de nvm

Une autre solution serait d’initialiser nvm uniquement lorsque l’on en a besoin. Quand on tapera une commande avec nvm, node ou npm par exemple. C’est du lazy loading. Ce serait l’idéal si on veut conserver nvm et que l’on veut éviter de ralentir le lancement du terminal.

Il est possible de le faire soi-même en créant quelques fonctions bash comme l’explique cet article. On peut aussi utiliser le système de plugin de zsh. Luke en a créé un pour nvm : zsh-nvm. J’ai opté pour cette solution.

  • La première étape est de supprimer les éventuelles instructions nvm de notre fichier .zshrc (cf. partie précédente).
  • On installe ensuite le plugin zsh-nvm.
  • On modifie le fichier .zshrc pour ajouter zsh-nvm dans la liste des plugins.
    • La ligne ressemble à plugins=(.......).
  • On indique au plugin que l’on veut du lazy loading.
    • On ajoute export NVM_LAZY_LOAD=true juste avant la liste des plugins.
  • On peut ajouter l’auto-complétion si nécessaire.
    • En ajoutant également export NVM_COMPLETION=true avant la liste des plugins.

Changer de version manager pour node

Vu que nvm est le fautif et qu’il existe d’autres version manager pour node, on peut se demander s’il en existe qui sont plus rapides.

Ça semble être le cas pour fnm (Fast Node Manager). Son nom est revenu plusieurs fois pendant mes recherches et dans les commentaires de personnes qui proposaient des alternatives au lazy loading de nvm. Je ne l’ai pas essayé.

Il y a également asdf, un outil unique qui propose de gérer les versions de multiples autres outils (node, Ruby, python, …). J’en parlais dans mon article sur les version manager. Il serait plus rapide que nvm d’après ce que j’ai lu. À tester. Je pense que je finirais par me passer de mes autres version manager pour tout regrouper avec asdf.


Quelques références de contenu que j’ai parcouru :