ビルドを壊さずに開発者キャッシュを消す
開発用のストレージは、パッケージのダウンロード、ビルド成果物、SDK、ローカルデータベース、プロジェクトごとの依存関係ツリーに散らばっています。再現できるもの、ロックファイルとあとで消えるかもしれないレジストリに依存するもの、そしてそのマシンだけが持つ固有データがあります。安全なクリーンアップは、ドットフォルダをすべてキャッシュだと決めつけず、見つかったものがどの種類かを確かめます。
ツール別のグローバルキャッシュ
各パッケージマネージャは、直接サイズを測れるグローバルストアを持っています。
du -sh ~/.npm ~/.cargo ~/.cache/pip ~/Library/Caches/pip ~/.gradle 2>/dev/null | sort -h
これらは既定の場所であり、絶対の保証ではありません。可能ならツール本体に設定パスを尋ねてください。たとえば npm config get cache、python -m pip cache dir、pnpm store path です。
- npm は既定で
~/.npmにダウンロードをキャッシュします。まずはnpm cache verifyから始めます。npm はキャッシュを自己修復できると説明しているため、npm cache clean --forceは主に意図的な空き容量の確保やトラブルシュート向けです。 - Cargo はレジストリと git のチェックアウトを
~/.cargo以下に置きますが、Cargo home にはインストール済みバイナリ、設定、パッケージ記録、レジストリの認証情報も含まれます。現行の Cargo は、ビルドや fetch の過程で未使用のグローバルキャッシュを定期的に削除します。その方針に任せるか、キャッシュのサブディレクトリを正確に確認してください。~/.cargo全体を消してはいけません。 - pip は既定で
~/Library/Caches/pipにホイールと HTTP レスポンスをキャッシュします。python -m pip cache infoで実際の場所とサイズを確認でき、python -m pip cache purgeで消去します。 - pnpm と yarn はそれぞれ独自のストアを持ちます。
pnpm store pruneとyarn cache cleanで、参照されていないパッケージやキャッシュ済みパッケージを整理できます。ストアのレイアウトやローカル/グローバルの挙動はバージョンで違うため、使っているパッケージマネージャの版を確認してください。 - Gradle と Maven(
~/.gradle、~/.m2)は、Android や JVM を扱う Mac では非常に大きくなりがちです。Gradle にはすでに 定期的なキャッシュクリーンアップ があります。手作業で見直す前にデーモンを止めてください。Maven リポジトリには、再ダウンロードできないローカルビルドや非公開アーティファクトが含まれることがあるため、既定ではリポジトリ全体を消さず、中身を確認してからにします。
コストには、大きな再ダウンロード、ネイティブの再ビルド、レジストリ上の版が消えたあとの過去ビルド失敗が含まれることがあります。ストアを再現可能だと呼ぶ前に、各依存関係のロックファイルと出所を確かめてください。
散らばった node_modules 問題
意外と大きいのは、単一のキャッシュではなく、触ったことのあるすべての JavaScript プロジェクトに散らばる node_modules フォルダです。それぞれが自己完結しており、しばしば 200〜500 MB あるため、古いプロジェクトが 10 個あるだけで数 GB が隠れます。場所とサイズを探すには次のとおりです。
find ~/www ~/Projects -name node_modules -type d -prune -exec du -sh {} + 2>/dev/null
例のルートは、実際にプロジェクトを置いているフォルダに置き換えてください。-prune は一致した依存関係ツリーの内部に find が入らないようにし、-exec はパス内の空白や特殊文字を安全に扱います。プロジェクトが依存関係を再構築できるのは、ソース、ロックファイル、パッケージマネージャの版、レジストリへのアクセス、必要なネイティブツールチェーンがすべてまだ使えるときだけです。それらの入力を残したうえで、ロックファイル向けのコマンド(例: npm ci)を使うのがよいです。
消してはいけないもの
パッケージキャッシュは置き換えられることがありますが、隣にある 2 つはそうではありません。プロジェクトの ソースとロックファイル(package.json、package-lock.json、Cargo.lock)はキャッシュではなくビルドの定義そのものなので、まとめて消してはいけません。また、プロジェクト間で共有している pnpm の content-addressed store のように、いま使っているグローバルストアは再ダウンロードで戻りますが、インストールの最中に消すと壊れることがあります。ビルドが走っていないときにキャッシュを消してください。
仕組み:content-addressed store と、node_modules が例外である理由
多くのパッケージマネージャは、繰り返しのダウンロードを減らすために content-addressed store を使います。pnpm はパッケージ版ごとのグローバルストアを 1 つ持ち、各プロジェクトの node_modules へ hard link するため、同じライブラリを使う 10 個のプロジェクトでもディスク上は 1 コピーで済みます。Cargo と Go のキャッシュも、ダウンロード内容を版やチェックサムでキーにします。これは整合性を守りますが、将来も取得できることを保証するものではありません。通常の npm インストールはプロジェクトごとに依存関係ツリーを実体化し、pnpm は共有ストアへプロジェクトをリンクできます。そのため、1 つの node_modules を消すことと、共有ストアを prune することでは、影響範囲が違います。
発見には地図、クリーンアップにはパッケージマネージャ
散らばり方こそが発見の問題です。Mole の Analyze ビューのような treemap は、どのプロジェクトやストアが大きいかを示せますが、パッケージマネージャ自身の verify、prune、clean コマンドは、そのインデックスと参照関係を理解しています。地図で対象を選び、所有者のツールで変更してください。
安全な作業の順番
ビルドとデーモンを止め、選んだプロジェクトルートを計測し、パッケージマネージャのストアを確認し、依存関係ツリーを消す前にソースとロックファイルを残します。ホームディレクトリのドットフォルダ全体を消すのではなく、文書化された prune コマンドを使います。ゴミ箱を空にする前に、1 つのプロジェクトを再ビルドしてください。目的は、再現に必要な情報を残したまま、再現可能な成果物だけを取り除くことです。