痛点:
npm2依赖不是扁平化的。所以出现了yarn和npm3,对包管理进行了扁平化,使得所有依赖的包都下载到同一级目录下。也就是说比如你安装一个 express,那么你会在 node_modules 下面只找到一个 express 的文件夹。而 express 依赖的项目都放在其文件夹下。
这个带来的问题或许 windows 用户深谙其痛,因为在这种安装环境下,会导致目录的层级特别高,而对于 windows 来说,最大的路径长度限制在 248 个字符,再加上 node_modules 这个单词又特别长。
扁平化后,存在的问题
1、幽灵依赖
“幽灵依赖” 指的是 项目中使用了一些 没有被定义在其 package.json 文件中 的 包。考虑下面的例子:
my-library/package.json
{
"name": "my-library",
"version": "1.0.0",
"main": "lib/index.js",
"dependencies": {
"minimatch": "^3.0.4"
},
"devDependencies": {
"rimraf": "^2.6.2"
}
}
复制代码
但假设代码是这样:
my-library/lib/index.js
var minimatch = require("minimatch")
var expand = require("brace-expansion"); // ???
var glob = require("glob") // ???
// (更多使用那些库的代码)
2、分身问题
node_modules
└─ demo-bar // v1.0.1
├─ index.js
└─ package.json
└─ demo-baz
├─ index.js
├─ package.json
└─ node_modules
└─ demo-bar // v1.0.0
├─ index.js
└─ package.json
└─ demo-foo
├─ index.js
├─ package.json
└─ node_modules
└─ demo-bar // v1.0.0
├─ index.js
└─ package.json
同一台电脑多项目开发下载的包重复,每个项目都要下载相应的包,使得在电脑磁盘中占用内存大。
pnpm优点:速度快,节省磁盘空间。
pnpm原理:
硬链接和软链接
pnpm 首先将依赖安装到全局 store,然后通过 symbolic link 和 hard link 来组织目录结构,将全局的依赖链接到项目中,将项目的直接依赖链接到 node_modules 的顶层,所有的依赖则平铺于 node_modules/.pnpm 目录下,实现了所有项目的依赖共享 store 的全局依赖,解决了幽灵依赖和 NPM 分身的问题
在 pnpm 中,会将依赖安装到当前分区的 <home dir>/.pnpm-store 位置中,可以通过以下命令获得当前的 store 位置:
pnpm store path
然后利用 hard link 将所需的包从 node_modules/.pnpm 硬链接到 store 中,最后通过 symbolic link 将 node_modules 中的顶层依赖以及依赖的依赖符号链接到 node_modules/.pnpm 中。
由于require('xxx')只会向node_module中查找相关依赖,并不会向.pnpm查找,所以不会有幽灵依赖的问题。而node_module中的是软链接,链接之后的文件在.pnpm中,.pnpm中又是依赖的硬链接,然后就可以从磁盘中找到依赖的文件