常见问题解答
为什么我的 node_modules
文件夹会占用磁盘空间,即使包存储在全局存储中?
pnpm 从全局存储创建到项目 node_modules
文件夹的硬链接。硬链接指向磁盘上原始文件所在的相同位置。因此,例如,如果您的项目中有一个名为 foo
的依赖项,它占用 1MB 的空间,那么它看起来像在项目的 node_modules
文件夹中占用 1MB 的空间,在全局存储中也占用相同数量的空间。但是,这 1MB 是磁盘上从两个不同位置访问的相同空间。因此,总的来说,foo
占用 1MB,而不是 2MB。
有关此主题的更多信息
它在 Windows 上运行吗?
简短回答:是的。长答案:在 Windows 上使用符号链接至少可以说是有问题的,但是,pnpm 有一个解决方法。对于 Windows,我们使用联接代替。
但是嵌套的 node_modules
方法与 Windows 不兼容?
早期版本的 npm 由于嵌套所有 node_modules
而存在问题(参见此问题)。但是,pnpm 不会创建深层文件夹,它会将所有包平坦地存储,并使用符号链接来创建依赖项树结构。
循环符号链接怎么样?
尽管 pnpm 使用链接将依赖项放入 node_modules
文件夹中,但会避免循环符号链接,因为父包会被放置在与它们的依赖项相同的 node_modules
文件夹中。因此,foo
的依赖项不在 foo/node_modules
中,而 foo
与它自己的依赖项一起位于 node_modules
中。
为什么根本要使用硬链接?为什么不直接符号链接到全局存储?
一个包可以在一台机器上具有不同的依赖项集。
在项目 A 中,[email protected]
的依赖项可以解析为 [email protected]
,但在项目 B 中,foo
的相同依赖项可能会解析为 [email protected]
;因此,pnpm 将 [email protected]
硬链接到使用它的每个项目,以便为它创建不同的依赖项集。
直接符号链接到全局存储可以使用 Node 的 --preserve-symlinks
标志,但是,这种方法会带来许多自身问题,因此我们决定坚持使用硬链接。有关做出此决定的更多详细信息,请参见此问题。
pnpm 是否可以在一个 Btrfs 分区中的不同子卷之间工作?
虽然 Btrfs 不允许在单个分区中的不同子卷之间进行跨设备硬链接,但它允许 reflinks。因此,pnpm 利用 reflinks 在这些子卷之间共享数据。
pnpm 是否可以在多个驱动器或文件系统之间工作?
包存储应该与安装位于同一个驱动器和文件系统上,否则包将被复制,而不是链接。这是由于硬链接工作方式的限制,即一个文件系统上的文件无法访问另一个文件系统中的位置。有关更多详细信息,请参见问题 #712。
pnpm 在以下两种情况下功能不同
指定存储路径
如果通过存储配置指定存储路径,则会在存储和位于不同磁盘上的任何项目之间进行复制。
如果您在磁盘 A
上运行 pnpm install
,则 pnpm 存储必须位于磁盘 A
上。如果 pnpm 存储位于磁盘 B
上,则所有必需的包将直接复制到项目位置,而不是链接。这会严重影响 pnpm 的存储和性能优势。
未指定存储路径
如果未设置存储路径,则会创建多个存储(每个驱动器或文件系统一个)。
如果在磁盘 A
上运行安装,则存储将在 A
上的文件系统根目录下创建 .pnpm-store
。如果稍后在磁盘 B
上运行安装,则将在 B
上的 .pnpm-store
处创建独立存储。项目仍然可以保持 pnpm 的优势,但每个驱动器可能会有冗余的包。
pnpm
代表什么?
pnpm
代表 performant npm
。 @rstacruz 想出了这个名字。
pnpm
不适用于 <YOUR-PROJECT-HERE>?
在大多数情况下,这意味着依赖项之一需要 package.json
中未声明的包。这是由扁平 node_modules
引起的常见错误。如果发生这种情况,这是依赖项中的错误,应该修复依赖项。但这可能需要时间,因此 pnpm 支持解决方法来使有问题的包正常工作。
解决方案 1
如果存在问题,您可以使用node-linker=hoisted
设置。这将创建一个类似于 npm
创建的扁平 node_modules
结构。
解决方案 2
在以下示例中,依赖项没有在其自己的依赖项列表中包含 iterall
模块。
解决有问题的包缺少依赖项的最简单方法是将 iterall
添加为我们项目 package.json
的依赖项。
您可以通过 pnpm add iterall
安装它,它将自动添加到您项目的 package.json
中。
"dependencies": {
...
"iterall": "^1.2.2",
...
}
解决方案 3
其中一个解决方案是使用钩子将缺少的依赖项添加到包的 package.json
中。
一个例子是Webpack Dashboard,它无法与 pnpm
一起使用。它现在已经得到解决,现在可以与 pnpm
一起使用。
它以前会抛出错误
Error: Cannot find module 'babel-traverse'
at /node_modules/[email protected]/node_modules/inspectpack/lib/actions/parse
问题是 babel-traverse
用于 inspectpack
中,而 inspectpack
用于 webpack-dashboard
,但 babel-traverse
未在 inspectpack
的 package.json
中指定。它仍然可以使用 npm
和 yarn
工作,因为它们创建扁平的 node_modules
。
解决方案是创建一个 .pnpmfile.cjs
,其内容如下
module.exports = {
hooks: {
readPackage: (pkg) => {
if (pkg.name === "inspectpack") {
pkg.dependencies['babel-traverse'] = '^6.26.0';
}
return pkg;
}
}
};
创建 .pnpmfile.cjs
后,仅删除 pnpm-lock.yaml
- 无需删除 node_modules
,因为 pnpm 钩子只影响模块解析。然后,重建依赖项,它应该可以工作。