常见问 题
如果包存储在全局存储中,为什么我的 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-traverse
在 inspectpack
中使用,而 inspectpack
又被 webpack-dashboard
使用,但 inspectpack
的 package.json
中没有指定 babel-traverse
。它仍然适用于 npm
和 yarn
,因为它们创建了平坦的 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.