缘起node_modules
很久以前,前端圈子里就流传着这么一张关于node_modules
的图
这就是当时的node_modules困境,当使用 npm 或 yarn 时,如果你有100个项目使用了某个依赖(dependency),就会有100份该依赖的副本保存在硬盘上。
虽然,从 npm3
开始,npm 维护了一个扁平依赖树 这导致磁盘空间减少, 但是 node_modules 目录依旧是混乱的。
这就催生出了后面的 pnpm
为什么会有pnpm
如上所述,当使用 npm 或 yarn 时,如果你有100个项目使用了某个依赖(dependency),就会有100份该依赖的副本保存在硬盘上。
而在使用 pnpm 时,依赖会被存储在内容可寻址存储
中,所以:
如果你用到了某依赖项的不同版本,那么只会将有差异的文件添加到仓库。 例如,如果某个包有100个文件,而它的新版本只改变了其中1个文件。那么 pnpm update 时只会向存储中心额外添加1个新文件,而不会因为仅仅一个文件的改变复制整新版本包的内容。
所有文件都会存储在硬盘上的某一位置。 当软件包被被安装时,包里的文件会硬链接到这一位置,而不会占用额外的磁盘空间。 这允许你跨项目地共享同一版本的依赖。
内容可寻址存储器cam(content-addressable memory):以内容进行寻址的存储器,是一种特殊的存储阵列ram。它的主要工作机制就是将一个输入数据项与存储在cam中的所有数据项自动同时进行比较,判别该输入数据项与cam中存储的数据项是否相匹配,并输出该数据项对应的匹配信息。
因此,您在磁盘上节省了大量空间,这与项目和依赖项的数量成正比,并且安装速度要快得多!
使用 npm 或 Yarn Classic 安装依赖项时,所有包都被提升到模块目录的根目录。 因此,项目可以访问到未被添加进当前项目的依赖。
默认情况下,pnpm 使用软链的方式将项目的直接依赖添加进模块文件夹的根目录。
pnpm的特点:
- 创建非扁平化的 node_modules 文件夹;
- 使用软链的方式将项目的直接依赖添加进模块文件夹的根目录。
安装pnpm
如果我们的设备安装了Node.js,那么可以直接使用npm进行安装
1
npm install -g pnpm
更多安装方式
使用pnpm
与 npm 不同的是,pnpm 会校验所有的参数。 比如,pnpm install –target_arch x64 会执行失败,因为 –target_arch x64 不是 pnpm install 的有效参数。
npm命令 | pnpm等效 |
---|---|
npm install | pnpm install |
npm i <pkg> |
pnpm add <pkg> |
npm run <cmd> |
pnpm <cmd> |
当你使用一个未知命令时, pnpm 会查找一个具有指定名称的脚本, 所以 pnpm run lint 和 pnpm lint相同. 如果没有指定名称的脚本,那么pnpm将以shell脚本的形式执行该命令,所以你可以做类似pnpm eslint的事情
pnpm VS. npm
npm的扁平树
从 npm v3 开始,npm 维护了一个扁平依赖树 这导致磁盘空间减少, 并且node_modules 目录是混乱的。
另一方面,pnpm 通过使用硬链接和符号链接链接到全局硬盘来管理node_modules。 这将使你的磁盘空间使用量大大减少,同时保持node_modules 的整洁。
pnpm 正确的 node_modules 结构的好处在于,它”有助于避免愚蠢的错误”,因为它让你无法使用不是 package.json 中指定的模块。
安装
pnpm 不允许安装 package.json 中没有包含的包。如果没有参数传递给 pnpm add,包将保存为常规依赖项。 与 npm 一样, –save-dev 和 –save-optional 可以是用于安装包作为开发或可选的依赖。
由于此限制,项目在使用 pnpm 时不会有任何无关的包,除非它们删除依赖项并将其保留为孤立的。这就是为什么 pnpm 的实现的 prune command 不允许你指定包来修剪 - 它总是去除所有多余的和孤儿包。
目录依赖
目录依赖以 file: 前缀开始,指向文件系统的目录。 与 npm 一样,pnpm 符号链接这些依赖项。 与 npm 不同的是,pnpm 不执行这些文件依赖项的安装。
这意味着如果您有一个名为 foo (<root>/foo
) 的包,它有 bar@file:../bar 作为依赖项,则当你在 foo 上执行 pnpm install 时, pnpm 将不会为 <root>/bar
安装。
如果您需要同时在多个包中运行安装,例如在 monorepo 的情况下,您应该查看 pnpm -r 的文档。