[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 中的包重復問題!

## 安裝
~~~
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