[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)
- 讲解 Markdown
- 示例
- SVN
- Git笔记
- github 相关
- DESIGNER'S GUIDE TO DPI
- JS 模块化
- CommonJS、AMD、CMD、UMD、ES6
- AMD
- RequrieJS
- r.js
- 模块化打包
- 学习Chrome DevTools
- chrome://inspect
- Chrome DevTools 之 Elements
- Chrome DevTools 之 Console
- Chrome DevTools 之 Sources
- Chrome DevTools 之 Network
- Chrome DevTools 之 Memory
- Chrome DevTools 之 Performance
- Chrome DevTools 之 Resources
- Chrome DevTools 之 Security
- Chrome DevTools 之 Audits
- 技巧
- Node.js
- 基础知识
- package.json 详解
- corepack
- npm
- yarn
- pnpm
- yalc
- 库处理
- Babel
- 相关库
- 转译基础
- 插件
- AST
- Rollup
- 基础
- 插件
- Webpack
- 详解配置
- 实现 loader
- webpack 进阶
- plugin 用法
- 辅助工具
- 解答疑惑
- 开发工具集合
- 花样百出的打包工具
- 纷杂的构建系统
- monorepo
- 前端工作流
- 爬虫
- 测试篇
- 综合
- Jest
- playwright
- Puppeteer
- cypress
- webdriverIO
- TestCafe
- 其他
- 工程开发
- gulp篇
- Building With Gulp
- Sass篇
- PostCSS篇
- combo服务
- 编码规范检查
- 前端优化
- 优化策略
- 高性能HTML5
- 浏览器端性能
- 前后端分离篇
- 分离部署
- API 文档框架
- 项目开发环境
- 基于 JWT 的 Token 认证
- 扯皮时间
- 持续集成及后续服务
- 静态服务器搭建
- mock与调试
- browserslist
- Project Starter
- Docker
- 文档网站生成
- ddd