常见问题
如果包存储在全局存储中,为什么我的 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 中,foo@1.0.0
的依赖可能解析为 bar@1.0.0
,但在项目 B 中,同样的 foo
依赖可能解析为 bar@1.1.0
;因此,pnpm 会在每个使用它的项目中为 foo@1.0.0
创建硬链接,以便为其创建不同的依赖集。
直接创建符号链接到全局存储虽然可以通过 Node.js 的 --preserve-symlinks
标志实现,但这种方法会带来很多其他问题,所以我们决定继续使用硬链接。关于为什么做出这个决定的更多详细信息,请参见这个问题。
pnpm 能在同一个 Btrfs 分区的不同子卷之间工作吗?
虽然 Btrfs 不允许在单个分区的不同子卷之间创建跨设备硬链接,但它允许使用 reflinks。因此,pnpm 利用 reflinks 在这些子卷之间共享数据。
pnpm 能跨多个驱动器或文件系统工作吗?
包存储应该与安装位置在同一个驱动器和文件系统上,否则包将被复制而不是链接。这是由于硬链接工作方式的限制,一个文件系统上的文件无法寻址另一个文件系统上的位置。更多详细信息请参见 Issue #712。
pnpm functions differently in the 2 cases below:
指定存储路径的情况
如果通过存储配置指定了存储路径,那么在存储和位于不同磁盘上的任何项目之间会进行复制。
如果你在磁盘 A
上运行 pnpm install
,那么 pnpm 存储必须在磁盘 A
上。
如果 pnpm 存储位于磁盘 B
上,那么所有需要的包都会直接复制到项目位置,而不是创建链接。这会严重影响 pnpm 的存储和性能优势。
未指定存储路径的情况
如果未设置存储路径,那么会创建多个存储(每个驱动器或文件系统一个)。
如果在磁盘 A
上运行安装,存储将在 A
的文件系统根目录下创建为 .pnpm-store
。如果稍后在磁盘 B
上运行安装,将在 B
上的 .pnpm-store
创建一个独立的存储。项目仍然保持 pnpm 的优势,但每个驱动器可能会有冗余的包。
pnpm
代表什么?
pnpm
代表 performant npm
(高性能的 npm)。
这个名字是由 @rstacruz 提出的。
pnpm
不能与 <YOUR-PROJECT-HERE> 一起使用?
在大多数情况下,这意味着其中一个依赖项需要未在 package.json
中声明的包。这是由扁平的
node_modules
导致的一个常见错误。如果发生这种情况,这是依赖项中的错误,应该修复该依赖项。
不过这可能需要一些时间,所以 pnpm 提供了一些解决方案来让有问题的包正常工作。
解决方案 1
如果遇到问题,你可以 使用 nodeLinker: 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/inspectpack@2.2.3/node_modules/inspectpack/lib/actions/parse
问题在于 babel-traverse
被 webpack-dashboard
使用的 inspectpack
使用,但 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 钩子只影响模块解析。
然后,重新构建依赖项,它应该就能正常工作了。