「依存関係の不法侵入」を許すな:pnpmの `–no-hoist` で実現する真の疎結合プロジェクト
こんにちは。開発環境の深淵を覗き続けてきたアーキテクトです。
フロントエンド開発の現場で、こんな経験はありませんか?
「`package.json` に書いていないはずのライブラリが、なぜか `import` できてしまう」
「別のライブラリをアップデートしたら、全く無関係な箇所でビルドエラーが発生した」
これらは、npmやYarnがデフォルトで行う「Hoisting(巻き上げ)」という挙動が引き起こす「依存関係の不法侵入」が原因です。今日は、pnpmという強力な武器を使い、この不確定要素を完全に排除する「隔離」の技術を伝授します。
—
1. なぜ「Hoisting(巻き上げ)」は諸刃の剣なのか
npmやYarnのデフォルト設定では、依存関係をフラットに配置しようとします。本来は「Aが依存するB」であるはずが、ルートの `node_modules` にBを無理やり引き上げる(Hoisting)ことで、インストール効率とディスク容量を改善しようとする仕組みです。
しかし、これには致命的な欠陥があります。
- 幽霊依存(Phantom Dependencies): `package.json` に明記していないライブラリが、たまたま他のライブラリの依存関係としてインストールされた結果、コードからインポートできてしまう。
- 暗黙の依存の固定化: 本来の依存元がそのライブラリを削除した瞬間、あなたのプロジェクトは突然壊れます。
pnpmは、シンボリックリンクを駆使して `node_modules` の構造を厳格に制御するツールです。今回は、その制御の究極系である `–no-hoist` を解説します。
—
2. 準備:pnpmを導入し、隔離の第一歩を踏み出す
まずは環境を整えましょう。まだインストールしていない場合は、OSの環境を選ばない最強のマネージャー「Corepack」経由で入れるのが現代の正解です。
Node.jsに内蔵されているCorepackを有効化
corepack enable
バージョンを確認
pnpm –version
プロジェクトの初期化
まずは実験用のディレクトリを作りましょう。
mkdir pnpm-strict-demo && cd pnpm-strict-demo
pnpm init
—
3. 禁断の `–no-hoist` 設定:依存関係を「監獄」へ
ここからが本題です。プロジェクトルートに `.npmrc` ファイルを作成し、以下の設定を書き込んでください。これが「不法侵入」を物理的に遮断するスイッチです。
`.npmrc`
すべてのパッケージの巻き上げを禁止する
hoist=false
特定のパッケージのみ許可したい場合は以下のように記述可能
public-hoist-pattern[]=@types/
この設定により、`node_modules` 内は「あなたが `package.json` に書いたもの」と「その子ライブラリが本当に必要としているもの」だけが厳格に管理されるようになります。
—
4. HelloWorld的な動作確認:隔離を証明する
本当に隔離されているか確認しましょう。例えば、`lodash` をインストールして、あえて「依存関係にないはずのライブラリ」を呼んでみます。
lodashのみインストール
pnpm add lodash
ここで、`index.js` を作成し、わざとインストールしていない `axios` を読み込んでみます。
`index.js`
import _ from ‘lodash’; // OK: package.jsonにある
import axios from ‘axios’; // ???:package.jsonにない
console.log(‘Hello, Strict World!’);
この状態で実行すると、TypeScriptやNode.jsのランタイムは、「axiosなんて見つからないよ」と即座に警告・エラーを出します。
従来(Hoistingあり)の場合: 運が良ければ他のパッケージ経由で `axios` が紛れ込んでおり、動いてしまっていたはずです。
今回(–no-hoist)の場合: 曖昧な依存は即座に排除されます。これが「再現性の高いビルド」を保証する第一歩です。
—
5. 現場のアーキテクトが教えるメリット・デメリット
この設定を採用することは、開発体験(DX)にどのような影響を与えるのでしょうか。
メリット
- ビルドの信頼性が激増: 開発環境、CI/CD、本番環境で「手元では動いたのに」というトラブルがほぼ消滅します。
- 依存関係の可視化: 「何を使っているか」が `package.json` を見るだけで100%正確に把握できます。
- アップグレード時の安全性: 不要な副作用に怯える必要がなくなり、ライブラリ更新が格段に楽になります。
デメリット(覚悟すべき点)
- 初期コスト: 依存の記述漏れがあると即座にエラーになるため、最初はエラー修正に追われるかもしれません。しかし、それは「本来直すべきだった隠れたバグ」の顕在化に過ぎません。
- 一部ツールの非互換: 古い開発ツールや、意図的に依存関係を無視する悪しき設計のライブラリが稀に動かなくなることがあります。その場合は `.npmrc` で個別に例外を設ける柔軟性も必要です。
—
まとめ:依存関係を支配する者が、開発を制する
「なんとなく動く」から「理由があって動く」環境へ。
pnpmの `–no-hoist` は、単なるパッケージ管理のオプションではなく、「プロジェクトの品質を担保するための契約書」です。
最初は厳しく感じるかもしれませんが、一度この「隔離されたクリーンな世界」を経験すると、もうHoistingの混沌には戻れなくなります。毎日のコーディングが劇的に楽になり、トラブルシューティングに費やす時間が激減するはずです。
さあ、今日からあなたのプロジェクトを「不法侵入者」から守りましょう。何か詰まったら、いつでも聞いてくださいね。応援しています!