pnpm憑什麼這麼快
- 2022 年 8 月 22 日
- 筆記
- javascript, pnpm, 前端包管理器, 拓展閱讀
前端包管理器層出不窮,pnpm算是一個後起之秀。它和npm有什麼不同,為什麼有了npm還要造一個pnpm?
npm的問題
npm是最早的包管理器,安裝nodejs自帶npm,v3版本之前,npm安全依賴的目錄結構是這樣的:
node_modules
└─ foo
├─ index.js
├─ package.json
└─ node_modules
└─ bar
├─ index.js
└─ package.json
結構清晰而直觀,但是存在一個明顯的問題,當依賴層級過多時,文件嵌套非常深,然而window系統對文件路徑長度是有限制的,超過256字元就會出現目標路徑太長,從而無法操作深層級文件的問題,從v3版本開始,npm將每個package平鋪到node_modules,就像這樣
node_modules
├─ foo
| ├─ index.js
| └─ package.json
└─ bar
├─ index.js
└─ package.json
平鋪的方式解決了長路徑的問題,但是又存在另一些問題:
package依賴不直觀,所有package都是平級的,無法看出來誰依賴了誰;
項目中可以直接import間接依賴的package,比如模組A依賴了模組B,開發者可以直接在項目中import模組B,當模組A升級之後,可能依賴的模組B版本也升級了,之前直接import模組B的API可能不再兼容;
除此之外,npm的另外一個問題是,如果你有10個項目中依賴了模組A,模組A將被安裝10次,並且在你的硬碟上保存了10份一模一樣的程式碼,佔用了大量磁碟空間
pnpm的作者意識到這些問題,站出來造了pnpm這個新輪子,加入了一些創新
pnpm的解決方案
pnpm的口號是「快速的,節省磁碟空間的包管理工具」,這就是pnpm名字的由來,pnpm代表 performant(高性能的)npm,那麼它是怎麼做到快且節省磁碟空間的?
當項目中安裝依賴包時,pnpm將所有依賴包存儲在磁碟的某一個位置,簡稱.pnpm store
,下次再安裝同一個包的時候,如果.pnpm store
已經存在這個包,將會在項目中創建一個硬鏈接到.pnpm store
(什麼是硬鏈接?),如果.pnpm store
不存在這個包,會先保存這個包到.pnpm store
,然後再創建硬鏈接。這樣設計,即使是10個項目都依賴了同一個版本的模組A,模組A也只在磁碟上保存1份程式碼,這就是pnpm又快又節省磁碟空間的原因
pnpm的實現方式
pnpm的node_modules並不是平鋪的,舉例:
某個項目使用了模組[email protected]
,模組[email protected]
又依賴了模組[email protected]
,那麼安裝依賴後的node_modules結構是這樣的:
node_modules
├── foo -> ./.pnpm/[email protected]/node_modules/foo
└── .pnpm
├── [email protected]
│ └── node_modules
│ └── bar -> <store>/bar
└── [email protected]
└── node_modules
├── foo -> <store>/foo
└── bar -> ../../[email protected]/node_modules/bar
node_modules根目錄下只有項目直接依賴的foo模組的軟鏈接和一個.pnpm隱藏文件夾,.pnpm文件夾內,以平鋪的方式存放著所有包,每個包文件夾都能一眼看出依賴關係
foo模組以及依賴的bar模組的真實文件,都是存放在.pnpm store
,通過硬鏈接的方式使用
總結
pnpm在重複安裝依賴包時,不需要複製文件,所以速度非常快,通過硬鏈接的方式共享同一份程式碼,極大的節省了磁碟空間
本文永久地址GitHub