📑

nvmを遅延ロードしてzsh起動を高速化する方法

に公開1

Node.jsの公式ドキュメントではnvmを使ったインストールが推奨されていますが、nvmを有効にするとシェル起動が遅くなります。

https://nodejs.org/ja/download

本記事では、nvmを遅延ロードすることでzshの起動を快適にする方法をご紹介します。

課題:nvmの自動読み込みがシェル起動を遅くする

公式インストーラーは.zshrcに以下の設定を追記します:

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

この設定により、zsh起動時に毎回nvm.shが読み込まれるため、プロンプトが表示されるまでにかなりの遅延が発生します。

解決策:nvmを遅延ロードする

以下の設定に置き換えることで、初回にnvmコマンドを実行したタイミングでのみnvm.shを読み込むようにします。これにより、シェル起動は高速のまま、nvmも通常どおり使えます。

if [ -d ${HOME}/.nvm ]; then
  # Set NVM_DIR if not already set
  export NVM_DIR="${NVM_DIR:-$HOME/.nvm}"

  # Lazy load NVM
  nvm() {
    unset -f nvm
    source "${NVM_DIR}/nvm.sh"
    nvm "$@"
  }

  # Add default Node version to PATH if it exists
  if [ -f "${NVM_DIR}/alias/default" ]; then
    DEFAULT_NODE_VERSION=$(cat "${NVM_DIR}/alias/default")
    NODE_BIN_PATH="${NVM_DIR}/versions/node/v${DEFAULT_NODE_VERSION}/bin"
    if [ -d "${NODE_BIN_PATH}" ]; then
      export PATH="${NODE_BIN_PATH}:$PATH"
      export NODE_PATH="${NVM_DIR}/versions/node/v${DEFAULT_NODE_VERSION}/lib/node_modules"
    fi
  fi
fi

注意点:上記コードではbash補完(bash_completion)を削除していますが、必要であれば同様に遅延ロードしてください。

遅延ロードの仕組み

  1. シェル起動時はnvm.shを読み込まないため、高速に起動
  2. nvmコマンドを呼ぶと関数nvm()が動作
  3. 関数内で実際のnvm.shを読み込み
  4. unset -f nvmで自身の関数定義を削除
  5. nvm "$@"で本来のnvmコマンドを再実行

必要な準備:デフォルトバージョンの設定

初回のシェル起動後に以下を実行して、デフォルトNodeバージョンを設定しておきます:

# installしたバージョンをdefaultに指定する
$ nvm alias default 22.17.0

この操作により、${HOME}/.nvm/alias/defaultにバージョン番号が書き込まれ、次回以降のシェル起動時に自動でそのバージョンのPATHが追加されます。

おまけ:.zshrcの上書きを防止する

bunもそうですが、フロントエンド界隈は.zshrcをインストール時に勝手に書き換えるソフトウェアが多い印象です。なぜこんなことをするのか理解できませんが、コミュニティとしてPATH周りのトラブル回避を優先しているためと推測します。

bunには.zshrc# bun completionsというコメントを追加しておくと追記をスキップする仕組みがあります。

https://github.com/oven-sh/bun/issues/7641

残念ながらnvmには同様の仕様がありません。そこでPRを出しました。

https://github.com/nvm-sh/nvm/pull/3613

マージされるかは不透明ですが、動向をチェックしてみてください。

Discussion

Seiki TokunagaSeiki Tokunaga

zshの起動が遅くてまさに困ってました。
この記事を参考に解決できました。
ありがとうございます!