新聞中心
概念
Fast, disk space efficient package manager。

從策劃到設(shè)計(jì)制作,每一步都追求做到細(xì)膩,制作可持續(xù)發(fā)展的企業(yè)網(wǎng)站。為客戶提供網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站、網(wǎng)站策劃、網(wǎng)頁設(shè)計(jì)、域名注冊(cè)、虛擬主機(jī)、網(wǎng)絡(luò)營銷、VI設(shè)計(jì)、 網(wǎng)站改版、漏洞修補(bǔ)等服務(wù)。為客戶提供更好的一站式互聯(lián)網(wǎng)解決方案,以客戶的口碑塑造優(yōu)易品牌,攜手廣大客戶,共同發(fā)展進(jìn)步。
快速的,節(jié)省磁盤空間的包管理工具。
特點(diǎn)
快速。pnpm 比替代方案快 2 倍數(shù)據(jù)來源[1]
- 高效。Node_modules 中的文件是從一個(gè)單一的可內(nèi)容尋址的存儲(chǔ)中鏈接過來的??梢岳斫獬梢粋€(gè)全局的 store 中獲取,后面會(huì)詳細(xì)提到。
- 支持 monorepos。pnpm 內(nèi)置支持了單倉多包。類似 --filter 后面接子 package 的 name 表示只把安裝的新包裝入這個(gè) package 中等。簡單實(shí)踐參考[2]。
- 嚴(yán)格。pnpm 默認(rèn)創(chuàng)建了一個(gè)非平鋪的 node_modules,因此代碼無法訪問任意包。
npm 和 yarn 包管理機(jī)制
npm@3 之前
采用的是一種嵌套安裝的方式。如下圖所示:
node_modules
└─ foo
├─ index.js
├─ package.json
└─ node_modules
└─ bar
├─ index.js
└─ package.json
缺點(diǎn):
- package 中經(jīng)常創(chuàng)建太深的依賴樹,這會(huì)導(dǎo)致 Windows 上的目錄路徑過長問題。
- 當(dāng)一個(gè) package 在不同的依賴項(xiàng)中需要時(shí),它會(huì)被多次復(fù)制粘貼并生成多份文件。
npm@3+ 以及 Yarn
將依賴偏平化:
node_modules
├─ foo
| ├─ index.js
| └─ package.json
└─ bar
├─ index.js
└─ package.json
缺點(diǎn):
- 幻影依賴(Phantom dependencies)?;糜耙蕾囍傅氖?node_modules 中的依賴包在沒有 package.json 。 中聲明的情況下使用了其他包的依賴
- 依賴結(jié)構(gòu)的不確定性。這里為什么是 [email protected] 提升,而不是 [email protected]?都有可能,跟安裝的順序有關(guān)。詳情可參考[3]。避免這個(gè)問題的解決方案:lock 文件。
- npm 包分身。同樣的也因?yàn)榇蚱搅?node_modules 中的依賴,就會(huì)造成了相同版本的子依賴包在被不同的項(xiàng)目依賴所依賴時(shí)會(huì)安裝兩次(即上面的圖,B/C 兩個(gè)包都依賴了 [email protected])。
安裝很慢。相同的包安裝了兩次,占用磁盤空間,相對(duì)的安裝的速度也會(huì)變慢。
非單例。當(dāng)兩個(gè)不同的組件調(diào)用 require("library-f") 時(shí),它們可能會(huì)得到兩個(gè)不同的庫實(shí)例,這意味著可能會(huì)突然出現(xiàn)兩個(gè)單例的實(shí)例(換言之,底層的 “global” 變量被分配到兩個(gè)不同的閉包中)。會(huì)使我們的調(diào)試變得非常困難。
pnpm 的解決方案
前置知識(shí)
inode
每一個(gè)文件都有一個(gè)唯一的 inode,它包含文件的元信息,在訪問文件時(shí),對(duì)應(yīng)的元信息會(huì)被 copy 到內(nèi)存去實(shí)現(xiàn)文件的訪問。
可以通過 stat 命令去查看某個(gè)文件的元信息。
stat README.md
hard link
硬鏈接可以理解為是一個(gè)相互的指針,創(chuàng)建的 hardlink 指向源文件的 inode,系統(tǒng)并不為它重新分配 inode。硬鏈接不管有多少個(gè),都指向的是同一個(gè) inode 節(jié)點(diǎn),這意味著當(dāng)你修改源文件或者鏈接文件的時(shí)候,都會(huì)做同步的修改。每新建一個(gè) hardlink 會(huì)把節(jié)點(diǎn)連接數(shù)增加,只要節(jié)點(diǎn)的鏈接數(shù)非零,文件就一直存在,不管你刪除的是源文件還是 hradlink。只要有一個(gè)存在,文件就存在。
.pnpm 中的每個(gè)文件都是來自內(nèi)容可尋址存儲(chǔ)的硬鏈接。
soft link
軟鏈接可以理解為是一個(gè)單向指針,是一個(gè)獨(dú)立的文件且擁有獨(dú)立的 inode,永遠(yuǎn)指向源文件,這就類比于 Windows 系統(tǒng)的快捷方式。刪除源文件,軟鏈接就會(huì)失效。
修改了軟鏈接或硬鏈接的文件,另外的硬鏈接或軟鏈接以及源文件都會(huì)發(fā)生變化,這里感覺是需要小心的,特別是修改文件以調(diào)試的時(shí)候,記得還原回去,否則另外一個(gè)項(xiàng)目用到的時(shí)候,可能會(huì)出問題。
幾個(gè)重點(diǎn)結(jié)果表現(xiàn)
項(xiàng)目根目錄下的 node_modules 中
node_modules 中只有直接依賴的包,而沒有間接依賴的包。通過軟鏈接到.pnpm 目錄中。
.pnpm
虛擬存儲(chǔ)目錄——.pnpm,所有直接和間接依賴項(xiàng)都鏈接到此目錄中。該目錄通過 @ 來實(shí)現(xiàn)相同模塊不同版本之間隔離和復(fù)用。
Store
pnpm在全局通過Store來存儲(chǔ)所有的 node_modules 依賴,并且在 .pnpm 中存儲(chǔ)項(xiàng)目的hard links。
在使用 pnpm 對(duì)項(xiàng)目安裝依賴的時(shí)候,如果某個(gè)依賴在 sotre 目錄中存在了話,那么就會(huì)直接從 store 目錄里面去 hard-link,避免了二次安裝帶來的時(shí)間消耗,如果依賴在 store 目錄里面不存在的話,就會(huì)去下載一次。
假如全局的包變得非常大怎么辦?使用方法為 pnpm store prune ,它提供了一種用于刪除一些不被全局項(xiàng)目所引用到的 packages 的功能,例如有個(gè)包 [email protected] 被一個(gè)項(xiàng)目所引用了,但是某次修改使得項(xiàng)目里這個(gè)包被更新到了 1.0.1 ,那么 store 里面的 1.0.0 的 axios 就就成了個(gè)不被引用的包,執(zhí)行 pnpm store prune 就可以在 store 里面刪掉它了。
原理分析
我們來看一張?jiān)韴D:
我們項(xiàng)目中有一個(gè)依賴 [email protected]。[email protected]也有一個(gè)依賴 [email protected]。
- node_modules 下面有 [email protected] 和 .pnpm 目錄,沒有 [email protected]。
- [email protected] 通過軟鏈接指向 .pnpm/[email protected]/node_modules/[email protected]。.pnpm/[email protected]/node_modules/[email protected] 又通過硬鏈接指向 Store。
- [email protected] 依賴的[email protected] 會(huì)安裝在跟自己的同一級(jí),這里的設(shè)計(jì),我理解是根據(jù) node 的 require 機(jī)制,bar 中 require('foo') 的時(shí)候,就會(huì)先找到 [email protected],而不會(huì)往上尋找,這樣就避免依賴包版本不一致的問題。.pnpm/[email protected]/node_modules/[email protected]。并通過軟鏈接指向 。
- pnpm 下一級(jí)的 [email protected]。
.pnpm/[email protected] 一樣通過硬鏈接指向 Store。
遷移和問題
我們現(xiàn)在可能用的是 npm 或者 yarn,那我們?nèi)绾胃玫倪^渡到 pnpm?或者會(huì)不會(huì)有什么問題?
- 遷移:
- 遷移 lock 文件??梢酝ㄟ^ pnpm import 的方式。參考[4]。
- 只允許使用 pnpm。參考[5]。
- 解決沖突。跟 npm 和 yarn 一樣。只需要解決完 package.json 的沖突,然后重新 install 即可。
- more...。
問題:
- CI/CD 中全局存儲(chǔ)的問題??赡軙?huì)命中不同的機(jī)器,也有可能存在權(quán)限的問題。
- 相比 npm、yarn。社區(qū)還沒那么活躍。
- 硬鏈接在 window 系統(tǒng)有兼容性的問題。
- more…。
總結(jié)
pnpm 通過巧妙硬鏈接 + 軟鏈接結(jié)合的方式完全實(shí)現(xiàn)了依賴樹結(jié)構(gòu)的 node_modules,并且嚴(yán)格遵循了 Node.js 的模塊解析標(biāo)準(zhǔn),解決了幻影依賴和 npm 分身的問題。并且通過全局只保存一份在 ~/.pnpm-store 的方式,在不同的項(xiàng)目中進(jìn)行 install 的速度也會(huì)變得更快,也解決了磁盤空間占用的問題。
參考資料
pnpm: 最先進(jìn)的包管理工具[6]
中文官網(wǎng)[7]
npm 存在的問題以及 pnpm 是怎么處理的[8]
[1]數(shù)據(jù)來源: https://github.com/pnpm/benchmarks-of-javascript-package-managers
[2]簡單實(shí)踐參考: https://zhuanlan.zhihu.com/p/373935751
[3]參考: http://npm.github.io/how-npm-works-docs/npm3/non-determinism.htm
l[4]參考: https://pnpm.io/zh/cli/import
[5]參考: https://pnpm.io/zh/only-allow-pnpm[6]pnpm: 最先進(jìn)的包管理工具: https://www.aisoutu.com/a/1218460
[7]中文官網(wǎng): https://www.pnpm.cn/
[8]npm 存在的問題以及 pnpm 是怎么處理的: https://www.yuexunjiang.me/blog/problems-with-npm-and-how-pnpm-handles-them/
分享標(biāo)題:高性能的包管理器Pnpm,你學(xué)會(huì)了嗎?
轉(zhuǎn)載來源:http://m.fisionsoft.com.cn/article/djiipie.html


咨詢
建站咨詢
