pnpm node_modules结构详细解释

213 阅读1分钟

1. pnpm 的 node_modules 结构

pnpm 是一个包管理工具,它通过符号链接(symlinks)来构建 node_modules 的结构。这种结构与传统的 npm 或 yarn 的方式不同,它更节省空间,也更严格地控制依赖的访问。

2. 硬链接和符号链接

  • 硬链接node_modules 中的每个包的文件实际上是存储在内容可寻址存储(content-addressable storage)中的硬链接。例如,foo@1.0.0bar@1.0.0 的文件会被硬链接到一个存储位置。
  • 符号链接:pnpm 使用符号链接来构建依赖关系。符号链接是一个指向实际文件的快捷方式。

3. 示例结构

假设你安装了 foo@1.0.0,它依赖于 bar@1.0.0,pnpm 会创建以下结构:

node_modules
└── .pnpm
    ├── bar@1.0.0
    │   └── node_modules
    │       └── bar
    │           ├── index.js     -> <store>/001
    │           └── package.json -> <store>/002
    └── foo@1.0.0
        └── node_modules
            └── foo
                ├── index.js     -> <store>/003
                └── package.json -> <store>/004
  • node_modules/.pnpm 是一个隐藏目录,用来存储每个包的实际文件。
  • foobar 的文件通过硬链接指向存储中的文件。

4. 构建依赖关系

接下来,pnpm 会通过符号链接来构建依赖关系:

node_modules
└── .pnpm
    ├── bar@1.0.0
    │   └── node_modules
    │       └── bar -> <store>
    └── foo@1.0.0
        └── node_modules
            ├── foo -> <store>
            └── bar -> ../../bar@1.0.0/node_modules/bar
  • foonode_modules 文件夹中有一个符号链接 bar,指向 bar@1.0.0 的实际位置。
  • 这样,foo 可以通过 require('bar') 正常访问 bar

5. 处理直接依赖

如果 foo 是项目的直接依赖,pnpm 会将 foo 符号链接到根目录的 node_modules 文件夹:

node_modules
├── foo -> ./.pnpm/foo@1.0.0/node_modules/foo
└── .pnpm
    ├── bar@1.0.0
    │   └── node_modules
    │       └── bar -> <store>
    └── foo@1.0.0
        └── node_modules
            ├── foo -> <store>
            └── bar -> ../../bar@1.0.0/node_modules/bar

6. 添加更多依赖

假设 barfoo 都依赖于 qar@2.0.0,pnpm 会继续使用符号链接来构建依赖关系:

node_modules
├── foo -> ./.pnpm/foo@1.0.0/node_modules/foo
└── .pnpm
    ├── bar@1.0.0
    │   └── node_modules
    │       ├── bar -> <store>
    │       └── qar -> ../../qar@2.0.0/node_modules/qar
    ├── foo@1.0.0
    │   └── node_modules
    │       ├── foo -> <store>
    │       ├── bar -> ../../bar@1.0.0/node_modules/bar
    │       └── qar -> ../../qar@2.0.0/node_modules/qar
    └── qar@2.0.0
        └── node_modules
            └── qar -> <store>