毎朝gulpが動かない問題を解決した話|node_modules・nvm・Homebrewの競合整理
こんにちは。いっきー(@ikirin_web)です。
favicon設置で詰まった話|Gitブランチ・node_modules・gulpの備忘録ではnode_modulesを消して再インストールする対処法を書きました。
その後nvmで切り替わらない原因を調べたら、Node.js関連ツールが3つ競合していた話でnvmのパスを追記する応急処置も試みました。
今回はその根本原因だった.zprofileの競合をようやく整理できた記録です。
PCを開いて npm run build を実行したら、またgulpが動かない。「Error: Cannot find module ‘…escalade/sync/index.js’」と表示される…
VS Codeを再起動するたびにこの症状が出ていて rm -rf node_modules && npm install で復旧していたのですが、根本解決できていませんでした。
今回、原因を徹底的に調べて解決したので記録として残しておきます。
※この記事は、実際に自分の環境で発生した問題を調査・解決した記録です。同じ症状でも原因が異なる場合があります。
環境
- macOS Tahoe 26(M2 MacBook Air)
- Node.js v18.20.8(nvm管理)
- Gulp 5
- VS Codeのターミナルを使用
問題の全体像
主な原因は、 nodebrew・nvm・HomebrewのNode.jsが競合していたことにありました。
VS Codeを開き直すたびにnodeのバージョンが変わり、node_modulesと合わなくなっていたようです。
同じプロジェクトなのに、起動するたびに違うNode.jsが使われていたんですよね。
何が原因でどう解決したのか解説します。
Node.jsの管理ツールが3つ競合していた
以下の確認コマンドを順番に実行したら、こうなっていました。
which node # /opt/homebrew/bin/node(Homebrewが勝っている)
nvm current # system(nvmが認識されていない)
which nodebrew # /Users/username/.nodebrew/current/bin/nodebrew(nodebrewも存在)
過去にnodebrew → Homebrew → nvmと乗り換えてきた経緯があり、古い管理ツールがPATHに残ったまま競合していました。
なぜ競合が起きるのか
ターミナルは $PATH に書かれた順番でコマンドを探します。
/opt/homebrew/bin ← Homebrewのnodeがここにいる
...(間にいろいろある)
/Users/username/.nvm/versions/node/v18.20.8/bin ← nvmのnodeはここ
Homebrewのインストール時に案内通り設定を追加すると、HomebrewがPATHの先頭に追加されます。そのため、ターミナルがnodeを探すとき常にHomebrewのnodeを先に見つけてしまい、nvmのnodeが使われない状態になっていました。
$PATH とは、コマンドの実体を探しに行く場所のリスト。左から順に探す
.zprofile がnvmを上書きしていた
以前のnvmで切り替わらない原因を調べたら、Node.js関連ツールが3つ競合していた話では、.zshrcの末尾にnvmのパスをPATHの先頭に追加する応急処置を行っていましたが、根本解決にはなっていませんでした。
次に.zprofileを確認したところ、自分では書いた記憶のないnodebrewやPython関連の設定が大量に残っていました。その中にHomebrewのPATHを先頭に追加する設定があり、これがnvmより優先されていたようです。
.zprofile → Macログイン時(ログインシェル)に読まれる。PATHなどの環境変数を設定するファイル
.zshrc → ターミナル(インタラクティブシェル)を開くたびに読まれる設定ファイル
解決手順
① バックアップを取る
cp ~/.zprofile ~/.zprofile.backup
設定ファイルを触る前は必ずバックアップを取ります。
② .zprofile をシンプルに書き換える
eval "$(/opt/homebrew/bin/brew shellenv)"
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
③ VS Codeのターミナルを開き直して確認
VS Codeのターミナルを一度閉じて、新しいターミナルを開きましょう。そして以下のコマンドを順番に実行していきます。
which node # /Users/username/.nvm/versions/node/v18.20.8/bin/node ✅
node -v # v18.20.8 ✅
nvm current # v18.20.8 ✅
nvmのnodeが正しく認識されました。
echo $PATH
# /Users/username/.nvm/versions/node/v18.20.8/bin:/opt/homebrew/bin:...
echo $PATHで確認すると、nvmがHomebrewより左側に表示されています。PATHは左から順に読まれるので、nvmが優先されている状態です。
.zprofileを整理後に npm run build を実行したら正常に動作して、毎回やっていた復旧作業が完全になくなりました。
まとめ:今回学んだこと
① Node.jsの管理ツールは一本化する
複数の管理ツールが混在するとPATHの競合が起きる。Node.jsの管理はnvmに一本化して、どのツールが使われているかを明確にしておく。
② 設定ファイルは .zshrc だけではない
.zprofile も確認する。読まれる順番が違うので、どちらに何を書くかが重要。
③ PATHは左から順番に読まれる
echo $PATH でPATHの中身を確認する癖をつける。どのコマンドが優先されているかがわかる。
今回は、AIに助けてもらいながら調査しました。.zprofile や .zshrc が何をするファイルなのかを調べつつ、PATH競合の原因を整理していきました。
AIで便利になったからこそ、なぜそうなるのか理解することを大事にしていきます。
おまけ:今回使った確認コマンド集
# どのnodeが使われているか確認
which node
node -v
nvm current
# PATHの中身を確認
echo $PATH
# 設定ファイルの中身を確認
cat ~/.zshrc
cat ~/.zprofile