フラットなnode_modulesは唯一の方法ではない
pnpmの新規ユーザーは、pnpmが作成するnode_modules
の奇妙な構造についてよく質問します。なぜフラットではないのでしょうか?すべてのサブ依存関係はどこにあるのでしょうか?
この記事の読者は、npmとYarnによって作成されたフラットな
node_modules
に既に精通していると仮定します。npm 3がv3でフラットなnode_modules
を使用し始めた理由がわからない場合は、なぜpnpmを使うべきなのか?でいくつかの前史を見つけることができます。
では、なぜpnpmのnode_modules
は普通ではないのでしょうか?2つのディレクトリを作成し、一方ではnpm add express
を、もう一方ではpnpm add express
を実行してみましょう。最初のディレクトリのnode_modules
の上部には次のようなものがあります。
.bin
accepts
array-flatten
body-parser
bytes
content-disposition
cookie-signature
cookie
debug
depd
destroy
ee-first
encodeurl
escape-html
etag
express
完全なディレクトリ構造はこちらで確認できます。
そして、これがpnpmによって作成されたnode_modules
です。
.pnpm
.modules.yaml
express
こちらで確認できます こちら。
では、すべての依存関係はどこにあるのでしょうか?node_modules
には.pnpm
というフォルダとexpress
というシンボリックリンクしかありません。expressしかインストールしていないため、アプリケーションがアクセスする必要があるのはこのパッケージだけです。
pnpmの厳格さがなぜ良いことなのかについては、こちらで詳しく説明しています。
express
の中身を見てみましょう。
▾ node_modules
▸ .pnpm
▾ express
▸ lib
History.md
index.js
LICENSE
package.json
Readme.md
.modules.yaml
express
にnode_modules
がありません!express
のすべての依存関係はどこにあるのでしょうか?
コツは、express
が単なるシンボリックリンクであることです。Node.jsは依存関係を解決する際に、実際の場所を使用するため、シンボリックリンクは保持しません。しかし、express
の実際の場所はどこにあるのでしょうか?
ここにあります: node_modules/.pnpm/express@4.17.1/node_modules/express.
わかりました。これで.pnpm/
フォルダの目的がわかりました。.pnpm/
はすべてのパッケージをフラットなフォルダ構造で格納するため、すべてのパッケージはこのパターンで名前付けされたフォルダにあります。
.pnpm/<name>@<version>/node_modules/<name>
これを仮想ストアディレクトリと呼びます。
このフラットな構造により、npm v2によって作成されたネストされたnode_modules
によって発生した長いパス問題を回避しますが、npm v3,4,5,6またはYarn v1によって作成されたフラットなnode_modules
とは異なり、パッケージを分離したままにします。
それでは、express
の実際の場所を見てみましょう。
▾ express
▸ lib
History.md
index.js
LICENSE
package.json
Readme.md
詐欺でしょうか?それでもnode_modules
がありません!pnpmのnode_modules
構造の2つ目のコツは、パッケージの依存関係が、依存パッケージの実際の場所と同じディレクトリレベルにあることです。そのため、express
の依存関係は.pnpm/express@4.17.1/node_modules/express/node_modules/
にはありませんが、.pnpm/express@4.17.1/node_modules/にあります。
▾ node_modules
▾ .pnpm
▸ accepts@1.3.5
▸ array-flatten@1.1.1
...
▾ express@4.16.3
▾ node_modules
▸ accepts
▸ array-flatten
▸ body-parser
▸ content-disposition
...
▸ etag
▾ express
▸ lib
History.md
index.js
LICENSE
package.json
Readme.md
express
のすべての依存関係は、node_modules/.pnpm/
内の適切なディレクトリへのシンボリックリンクです。express
の依存関係を一つ上のレベルに配置することで、循環シンボリックリンクを回避できます。
ご覧のように、pnpmのnode_modules
構造は最初は変わって見えますが、
- 完全にNode.jsと互換性があります。
- パッケージは依存関係とともに適切にグループ化されています。
ピア依存関係を持つパッケージについては、構造はもう少し複雑ですが、フラットなディレクトリ構造でネストを作成するためのシンボリックリンクを使用するという考え方は同じです。