Skip to main content
Version: 9.x

常见问题

如果包存储在全局存储中,为什么我的 node_modules 文件夹会占用磁盘空间?

¥Why does my node_modules folder use disk space if packages are stored in a global store?

pnpm 从全局存储创建 硬链接 到项目的 node_modules 文件夹。硬链接指向磁盘上原始文件所在的同一位置。因此,例如,如果你的项目中有 foo 作为依赖,并且它占用了 1MB 的空间,那么看起来它在项目的 node_modules 文件夹中占用了 1MB 的空间,并且在全局存储中占用了相同的空间量。然而,这 1MB 是磁盘上从两个不同位置寻址的相同空间。所以总共 foo 占用 1MB,而不是 2MB。

¥pnpm creates hard links from the global store to the project's node_modules folders. Hard links point to the same place on the disk where the original files are. So, for example, if you have foo in your project as a dependency and it occupies 1MB of space, then it will look like it occupies 1MB of space in the project's node_modules folder and the same amount of space in the global store. However, that 1MB is the same space on the disk addressed from two different locations. So in total foo occupies 1MB, not 2MB.

有关此主题的更多信息:

¥For more on this subject:

它可以在 Windows 上运行吗?

¥Does it work on Windows?

简短回答:是的。长答案:至少可以说,在 Windows 上使用符号链接是有问题的,但是 pnpm 有一个解决方法。对于 Windows,我们使用 junctions

¥Short answer: Yes. Long answer: Using symbolic linking on Windows is problematic to say the least, however, pnpm has a workaround. For Windows, we use junctions instead.

但是嵌套 node_modules 方法与 Windows 不兼容?

¥But the nested node_modules approach is incompatible with Windows?

npm 的早期版本由于嵌套所有 node_modules 而存在问题(请参阅 此问题)。然而,pnpm 不会创建深层文件夹,它扁平地存储所有包并使用符号链接来创建依赖树结构。

¥Early versions of npm had issues because of nesting all node_modules (see this issue). However, pnpm does not create deep folders, it stores all packages flatly and uses symbolic links to create the dependency tree structure.

¥What about circular symlinks?

尽管 pnpm 使用链接将依赖放入 node_modules 文件夹中,但可以避免循环符号链接,因为父包被放入其依赖所在的同一个 node_modules 文件夹中。所以 foo 的依赖不在 foo/node_modules 中,但是 foo 连同它自己的依赖都在 node_modules 中。

¥Although pnpm uses linking to put dependencies into node_modules folders, circular symlinks are avoided because parent packages are placed into the same node_modules folder in which their dependencies are. So foo's dependencies are not in foo/node_modules, but foo is in node_modules together with its own dependencies.

¥Why have hard links at all? Why not symlink directly to the global store?

一个包在一台机器上可以有不同的依赖集。

¥One package can have different sets of dependencies on one machine.

在项目 A 中,foo@1.0.0 可以将依赖解析为 bar@1.0.0,但在项目 B 中,foo 的相同依赖可能会解析为 bar@1.1.0;因此,pnpm 将 foo@1.0.0 硬链接到使用它的每个项目,以便为其创建不同的依赖集。

¥In project A foo@1.0.0 can have a dependency resolved to bar@1.0.0, but in project B the same dependency of foo might resolve to bar@1.1.0; so, pnpm hard links foo@1.0.0 to every project where it is used, in order to create different sets of dependencies for it.

直接符号链接到全局存储可以与 Node 的 --preserve-symlinks 标志配合使用,但是,这种方法本身有很多问题,因此我们决定坚持使用硬链接。有关做出此决定的更多详细信息,请参阅 此问题

¥Direct symlinking to the global store would work with Node's --preserve-symlinks flag, however, that approach comes with a plethora of its own issues, so we decided to stick with hard links. For more details about why this decision was made, see this issue.

pnpm 是否可以跨一个 Btrfs 分区中的不同子卷工作?

¥Does pnpm work across different subvolumes in one Btrfs partition?

虽然 Btrfs 不允许单个分区中不同子卷之间的跨设备硬链接,但它允许重新链接。因此,pnpm 利用引用链接在这些子卷之间共享数据。

¥While Btrfs does not allow cross-device hardlinks between different subvolumes in a single partition, it does permit reflinks. As a result, pnpm utilizes reflinks to share data between these subvolumes.

pnpm 可以跨多个驱动器或文件系统工作吗?

¥Does pnpm work across multiple drives or filesystems?

软件包存储应与安装位于同一驱动器和文件系统上,否则软件包将被复制,而不是链接。这是由于硬链接工作方式的限制,一个文件系统上的文件无法寻址另一个文件系统中的位置。详细信息请参见 问题 #712

¥The package store should be on the same drive and filesystem as installations, otherwise packages will be copied, not linked. This is due to a limitation in how hard linking works, in that a file on one filesystem cannot address a location in another. See Issue #712 for more details.

pnpm 在以下两种情况下的功能有所不同:

¥pnpm functions differently in the 2 cases below:

存储路径已指定

¥Store path is specified

如果通过 存储配置 指定存储路径,则在存储和不同磁盘上的任何项目之间发生复制。

¥If the store path is specified via the store config, then copying occurs between the store and any projects that are on a different disk.

如果在磁盘 A 上运行 pnpm install,则 pnpm 存储必须位于磁盘 A 上。如果 pnpm 存储位于磁盘 B 上,则所有必需的包将直接复制到项目位置,而不是链接。这严重抑制了 pnpm 的存储和性能优势。

¥If you run pnpm install on disk A, then the pnpm store must be on disk A. If the pnpm store is located on disk B, then all required packages will be directly copied to the project location instead of being linked. This severely inhibits the storage and performance benefits of pnpm.

存储路径未指定

¥Store path is NOT specified

如果未设置存储路径,则会创建多个存储(每个驱动器或文件系统一个)。

¥If the store path is not set, then multiple stores are created (one per drive or filesystem).

如果安装在磁盘 A 上运行,则存储将在文件系统根目录下的 A .pnpm-store 上创建。如果稍后在磁盘 B 上运行安装,则会在 B.pnpm-store 上创建一个独立存储。这些项目仍将保留 pnpm 的优点,但每个驱动器可能具有冗余包。

¥If installation is run on disk A, the store will be created on A .pnpm-store under the filesystem root. If later the installation is run on disk B, an independent store will be created on B at .pnpm-store. The projects would still maintain the benefits of pnpm, but each drive may have redundant packages.

pnpm 代表什么?

¥What does pnpm stand for?

pnpm 代表 performant npm@rstacruz 想出了这个名字。

¥pnpm stands for performant npm. @rstacruz came up with the name.

pnpm 不适用于 <YOUR-PROJECT-HERE>?

¥pnpm does not work with <YOUR-PROJECT-HERE>?

在大多数情况下,这意味着依赖之一需要未在 package.json 中声明的包。这是扁平 node_modules 引起的常见错误。如果发生这种情况,则这是依赖中的错误,应修复依赖。但这可能需要时间,因此 pnpm 支持解决方法以使有问题的包正常工作。

¥In most cases it means that one of the dependencies require packages not declared in package.json. It is a common mistake caused by flat node_modules. If this happens, this is an error in the dependency and the dependency should be fixed. That might take time though, so pnpm supports workarounds to make the buggy packages work.

解决方案 1

¥Solution 1

如果出现问题,你可以使用 node-linker=hoisted 设置。这将创建一个类似于 npm 创建的扁平 node_modules 结构。

¥In case there are issues, you can use the node-linker=hoisted setting. This creates a flat node_modules structure similar to the one created by npm.

解决方案 2

¥Solution 2

在以下示例中,依赖在其自己的依赖列表中没有 iterall 模块。

¥In the following example, a dependency does not have the iterall module in its own list of deps.

解决有问题的包缺少依赖的最简单解决方案是将 iterall 添加为我们项目的 package.json 的依赖。

¥The easiest solution to resolve missing dependencies of the buggy packages is to add iterall as a dependency to our project's package.json.

你可以通过 pnpm add iterall 安装它来执行此操作,并将自动添加到你项目的 package.json 中。

¥You can do so, by installing it via pnpm add iterall, and will be automatically added to your project's package.json.

  "dependencies": {
...
"iterall": "^1.2.2",
...
}

解决方案 3

¥Solution 3

解决方案之一是使用 hooks 将缺少的依赖添加到包的 package.json 中。

¥One of the solutions is to use hooks for adding the missing dependencies to the package's package.json.

一个例子是 Webpack 仪表板,它不能与 pnpm 一起使用。此问题已得到解决,现在可以与 pnpm 一起使用。

¥An example was Webpack Dashboard which wasn't working with pnpm. It has since been resolved such that it works with pnpm now.

它曾经抛出一个错误:

¥It used to throw an error:

Error: Cannot find module 'babel-traverse'
at /node_modules/inspectpack@2.2.3/node_modules/inspectpack/lib/actions/parse

问题是 babel-traverseinspectpack 中使用,而 inspectpack 又被 webpack-dashboard 使用,但 inspectpackpackage.json 中没有指定 babel-traverse。它仍然适用于 npmyarn,因为它们创建了平坦的 node_modules

¥The problem was that babel-traverse was used in inspectpack which was used by webpack-dashboard, but babel-traverse wasn't specified in inspectpack's package.json. It still worked with npm and yarn because they create flat node_modules.

解决方案是创建一个包含以下内容的 .pnpmfile.cjs

¥The solution was to create a .pnpmfile.cjs with the following contents:

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 钩子仅影响模块解析。然后,重建依赖,它应该可以工作。

¥After creating a .pnpmfile.cjs, delete pnpm-lock.yaml only - there is no need to delete node_modules, as pnpm hooks only affect module resolution. Then, rebuild the dependencies & it should be working.