
pnpmで特定パッケージだけビルドキャッシュの再利用を除外する
どうも!オペ部の西村祐二です!
システムの共有ライブラリに依存するパッケージでは、パッケージのバージョンが同じでもビルド結果を使い回したくない場合があります。pnpmの12.14.0で追加されたsideEffectsCache.excludeを使うと、指定したパッケージだけビルド結果のキャッシュ再利用から外せます。
除外するパッケージ名を指定する
pnpm 12.14.0以降では、プロジェクト直下のpnpm-workspace.yamlに次の設定を書きます。cache-demo-addonは、後半で使うサンプルのパッケージ名です。実際の利用時は、除外したい依存パッケージ名を指定します。
sideEffectsCache:
exclude:
- cache-demo-addon
この指定だけで、他のパッケージのside-effects cacheの読み書きは既定の有効状態を保ちます。設定後のインストールは、通常どおりです。
pnpm install
対象パッケージは、ローカル・リモートのside-effects cacheからビルド結果を復元せず、保存もしません。ダウンロードしたパッケージ本体のキャッシュを無効にする設定ではありません。また、ビルドスクリプトの実行許可は別に必要です。既存のnode_modulesがある状態での再ビルドまでは、この記事では確認していません。以下ではnode_modulesを削除して比較します。
同じ依存を入れ直して比較する
Ubuntu 24.04.5 / Linux arm64、Node.js 24.21.0、pnpm 12.14.0で確認しました。ネイティブモジュールのコンパイルの代わりに、環境変数の値をファイルに書くpostinstallを使い、ビルドが再実行されたかを見ます。
1. ビルド結果を残すパッケージを用意する
pnpm 12.14.0とNode.jsが使える環境で、新しいサンプル用ディレクトリを作ります。
mkdir pnpm-cache-demo
cd pnpm-cache-demo
mkdir package
cd package
package内に次の2ファイルを保存します。
{"name":"cache-demo-addon","version":"1.0.0","scripts":{"postinstall":"node build.cjs"}}
const fs = require('node:fs');
fs.writeFileSync('built.txt', process.env.BUILD_MARKER || 'unset');
パッケージをtarballにして、サンプルのルートへ戻ります。
pnpm pack --pack-destination ..
cd ..
2. キャッシュを有効にした状態で入れ直す
ルートに次の2ファイルを保存します。ビルド許可には、今回のfile:依存を表すキーを指定しています。
{"name":"cache-demo-app","version":"1.0.0","private":true,"dependencies":{"cache-demo-addon":"file:cache-demo-addon-1.0.0.tgz"}}
storeDir: .pnpm-store
updateNotifier: false
enableGlobalVirtualStore: false
permissions:
cache-demo-addon@file:cache-demo-addon-1.0.0.tgz:
build: true
この例ではサンプル専用のstoreを使い、global virtual storeを無効にして比較条件をそろえます。以下のrm -rf node_modulesは、この新規サンプル内の依存を入れ直すための操作です。
BUILD_MARKER=first pnpm install
cat node_modules/cache-demo-addon/built.txt
rm -rf node_modules
BUILD_MARKER=second pnpm install --frozen-lockfile
cat node_modules/cache-demo-addon/built.txt
どちらもfirstになりました。2回目は環境変数をsecondに変えても、最初のビルド結果がキャッシュから復元されています。
3. 除外設定を追加して入れ直す
先ほどのpnpm-workspace.yamlの末尾に、冒頭のsideEffectsCacheブロックを追加します。既存のビルド許可は残します。
rm -rf node_modules
BUILD_MARKER=third pnpm install --frozen-lockfile
cat node_modules/cache-demo-addon/built.txt
rm -rf node_modules
BUILD_MARKER=fourth pnpm install --frozen-lockfile
cat node_modules/cache-demo-addon/built.txt
今度は順にthird、fourthになりました。同じtarballを使ったまま、それぞれのインストールでpostinstallが実行されています。
次の画像は比較結果をファイルに記録し、ターミナルに表示したものです。最後の行は、除外設定を外してもう一度入れ直した追加確認です。

除外を解除すると古いキャッシュが再利用される
sideEffectsCacheブロックを削除し、ビルド許可などは残したまま、もう一度入れ直します。
rm -rf node_modules
BUILD_MARKER=fifth pnpm install --frozen-lockfile
cat node_modules/cache-demo-addon/built.txt
結果はfirstに戻りました。除外中に作ったthirdやfourthではなく、除外前のキャッシュが残っていました。
この設定はキャッシュの読み書きを省くためのもので、既存のビルドキャッシュを削除する操作ではありません。除外対象を戻すときは、この違いを踏まえる必要があります。
公式ドキュメントでは、名前のほかに@scope/*や、完全一致バージョンを付けた指定も案内されています。今回は名前だけを指定した、ローカルtarball依存の動作に絞りました。リモートキャッシュ、global virtual storeでのプロジェクト間共有、実際のネイティブモジュール、macOS・Windowsでの動作は検証対象に含めていません。
まとめ
pnpmのsideEffectsCache.excludeにパッケージ名を書くと、その依存を、ビルド結果のキャッシュ再利用の対象から外せました。共有ライブラリなど、キャッシュキーに含まれない条件がビルド結果を左右するパッケージに使う設定です。既存キャッシュの削除や、ビルドスクリプトの実行許可とは役割が異なります。
参考リンク:








