シンボリックリンクを使用した `node_modules` の構造
情報
この記事では、ピア依存関係のパッケージが存在しない場合、pnpm が node_modules をどのように構成するのか説明します。 ピア依存関係を含むより複雑な状況については、ピア依存関係の解決方法を参照してください。
pnpmは入れ子になった依存関係をシンボリックリンクを使用してnode_modulesに配置します。
node_modulesに存在する全てのパッケージに含まれるそれぞれのファイルは、コンテンツストアへのハードリンクです。 依存関係にbar@1.0.0を持つfoo@1.0.0をインストールするところを見ていきましょう。 pnpmはnode_modulesにそれぞれのパッケージのハードリンクを作成します。
node_modules
└── .pnpm
    ├── bar@1.0.0
    │   └── node_modules
    │       └── bar -> <store>/bar
    │           ├── index.js
    │           └── package.json
    └── foo@1.0.0
        └── node_modules
            └── foo -> <store>/foo
                ├── index.js
                └── package.json
これらのファイルはnode_modulesにおいて唯一の「実体のある」ファイルです。 すべてのパッケージについてnode_modulesにハードリンクを作成したら、入れ子になった依存関係のグラフ構造を反映するシンボリックリンクを作成します。
お気づきのとおり、どちらのパッケージもそれぞれのサブディレクトリnode_modulesへ自身のハードリンクを作成しています (foo@1.0.0/node_modules/foo) 。 このハードリンクが必要な理由は次のとおりです。
- **パッケージが自分自身をインポートできるようにするため。**たとえばパッケージ
fooでrequire('foo/package.json')あるいはimport * as package from "foo/package.json"のように記述できるようにするためです。 - **シンボリックリンクの循環参照を避けるため。**あるパッケージの依存パッケージは、同 じディレクトリ階層に並んでいます。 Node.jsの場合、依存パッケージがパッケージ自身の
node_modulesにあっても、上位階層のどこかのnode_modulesにあっても違いはありません。 
インストールの次の段階では、依存関係同士をシンボリックリンクで結びつけます。 たとえば、barのシンボリックリンクをfoo@1.0.0/node_modulesに作成します。
node_modules
└── .pnpm
    ├── bar@1.0.0
    │   └── node_modules
    │       └── bar -> <store>/bar
    └── foo@1.0.0
        └── node_modules
            ├── foo -> <store>/foo
            └── bar -> ../../bar@1.0.0/node_modules/bar