ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
[TOC] # pnpm [速度快、节省磁盘空间的软件包管理器 | pnpm 中文文档 | pnpm 中文网](https://www.pnpm.cn/) # pnpm 的方案 ## 硬链接(hard link)节约磁盘空间 > 硬链接以理解为源文件的副本,使得用户可以通过不同的路径引用方式去找到某个文件,他和源文件一样的大小但是事实上却不占任何空间。 pnpm 会在全局 store 目录里存储项目 node_modules 文件的硬链接。硬链接可以使得不同的项目可以从全局 store 寻找到同一个依赖,大大节省了磁盘空间。该策略会将包安装在系统的全局 store 中,依赖的每个版本只会在系统中安装一次。 ## 符号链接(symbolic link)创建嵌套结构 > 软链接可以理解为快捷方式,pnpm在引用依赖时通过符号链接去找到对应磁盘目录(`.pnpm`)下的依赖地址。非扁平化结构。 pnpm 使用`.pnpm`目录以平铺的形式储存着所有的包。 该目录通过`@`来实现相同模块不同版本之间隔离和复用,由于它只会根据项目中的依赖生成,并不存在提升,所以它不会存在之前提到的幽灵依赖(Phantom dependencies)问题! 然后使用 store + Links 和文件资源进行关联。简单说pnpm 把会包下载到一个公共目录,如果某个依赖在 sotre 目录中存在了话,那么就会直接从 store 目录里面去 hard-link,避免了二次安装带来的时间消耗,如果依赖在 store 目录里面不存在的话,就会去下载一次。 通过 store + hard link 的方式,不仅解决了项目中的 NPM分身(NPM doppelgangers)问题(当包有多个版本,会被重复安装多次),项目之间也不存在该问题,从而完美解决了npm3+ 和 yarn 中的包重复问题! ![](https://img.kancloud.cn/e7/8f/e78f24d70a97ebf56dae51f1b1717a1a_2920x1392.png) ## 安装 ~~~ npm install -g pnpm npx pnpm add -g pnpm ~~~ ## 升级 让 pnpm 自己来更新自己,如下所示: ~~~ pnpm add -g pnpm ~~~ 你是否需要在 CI 服务器上使用 pnpm?请参阅[持续集成](https://www.pnpm.cn/continuous-integration)章节。 ~~~sh pnpm install # 安装所有依赖 pnpm add <pkg> # 安装依赖 pnpm rm <pkg> # 删除依赖 pnpm up <pkg> # 更新依赖 ~~~ # workspace ## 开始 安装 pnpm,然后`init`一个项目。 在根目录中新建 `pnpm-workspace.yaml`,内容如下 ~~~yaml packages: # 所有在 packages/ 子目录下的 package - 'packages/**' ~~~ 我们所有的`packages`都放在 `packages` 目录下。 用 pnpm 安装全局共用的包,比如 react, react-dom。 在顶层安装全局依赖的命令如下: ``` pnpm add -w react react-dom pnpm add -D -w typescript ``` 注意这里使用 `-w` 表示把包安装在 root 下,该包会放置在 `<root>/node_modules` 下。当然也可以把它安装在所有 packages 中,使用 `-r` 代替 `-w`。 > [pnpm recursive | pnpm](https://pnpm.io/zh/cli/recursive) ## 子包依赖 例如把`packages`下的`@test/utils`装入`packages/web`下 `package.json`的`name`为 `@test/web`包中。需要执行: ~~~sh pnpm i @test/utils -r --filter @test/ui ~~~ 使用 `--filter` 后面接子 package 的 name 表示只把安装的新包装入这个`package`中。 这里`--filter`参数即特定要作用到哪个子项目,详见:[pnpm 过滤](https://pnpm.io/zh/filtering)。里面还是比较详细的,有 可以对该包和所有依赖该包的其他包执行命令,等等。 默认情况下,为了节省时间和空间,pnpm 会默认不在子项目中软链接顶层安装的全局依赖,如需关闭这一行为(不推荐),可以在项目根目录的`.npmrc`配置: ``` shared-workspace-lockfile=false ``` ## 增加全局命令 假定我们有两个子项目,分别为`@test/app1`和`@test/app2`(这里指的是所在子项目的`package.json`里的`name`名字): 那么在项目根目录`package.json`配置项目启动命令: ``` "scripts": { "dev:app1": "pnpm start --filter @test/app1", "dev:app2": "pnpm start --filter @test/app2" }, ``` # 参考 [npm、yarn、pnpm - 掘金](https://juejin.cn/post/7125083641822052383) [工作空间 | pnpm](https://pnpm.io/zh/workspaces#workspace-protocol-workspace)