淺談 npm/yarn/pnpm

npm /yarn 原理

依賴地獄

早期的 npm 會(huì)直接安裝依賴舔箭,如果依賴存在依賴罩缴,則在依賴?yán)锛尤?node_modules。

假如有兩個(gè)依賴 A, BA 依賴于 C D,而 B 依賴于 C E靴庆。則依賴目錄是這樣的:

node_modules
├─ A
│  └─ node_modules
│     └─ C
│     └─ D
├─ B
│  └─ node_modules
│     └─ C
└─    └─ E

從依賴目錄可以看出,假如A依賴于C@1.0.0, B也依賴于C@1.0.0怒医。則會(huì)同時(shí)安裝兩份C@1.0.0炉抒。很明顯,有一份C@1.0.0是重復(fù)的稚叹。

對(duì)于大型項(xiàng)目焰薄,依賴會(huì)特別多,個(gè)別依賴也會(huì)嵌套比較深扒袖。這樣就會(huì)導(dǎo)致不同的依賴分支里會(huì)有大量的重復(fù)依賴塞茅,且依賴嵌套過深的話會(huì)導(dǎo)致 windows 目錄路徑過長問題。由于是嵌套導(dǎo)致的季率,這個(gè)時(shí)期的依賴安裝被稱為依賴地獄野瘦。

依賴扁平化

為了解決依賴嵌套的問題, npm3.x 開始(yarn 也是這個(gè)時(shí)期出現(xiàn)的)飒泻,開始依賴扁平化鞭光。也就是把依賴的依賴提升到 node_modules 根目錄下,重復(fù)的依賴不再安裝泞遗。這樣就可以實(shí)現(xiàn)依賴共享惰许。

比如上面這個(gè)例子,依賴目錄如下:

node_modules
├─ A
├─ B
├─ C@1.0.0
├─ D
└─ E

這樣好像解決了重復(fù)依賴的問題史辙?只能說是解決了汹买,但沒有完全解決

假如 A 依賴于 C@1.0.0D聊倔,B 依賴于 C@2.0.0E 晦毙,同時(shí) E 又依賴于 C@2.0.0。則依賴扁平化的安裝如下:

node_modules
├─ A
├─ C@1.0.0
├─ D
├─ B
│  └─ node_modules
│     └─ C@2.0.0
│─ E
│  └─ node_modules
└─    └─ C@2.0.0

安裝的時(shí)候耙蔑,C@1.0.0 D E 會(huì)被提升到 node_modules 根目錄结序。但是由于版本不一致,BE 依賴的 C@2.0.0就只能放到自身的 node_modules 下纵潦,而不能共享提升的 C@1.0.0徐鹤。這樣一來 C@2.0.0 就被安裝了兩份。

C@2.0.0被叫做分身依賴邀层。分身依賴就是相同版本的依賴被重復(fù)安裝返敬。

除了分身依賴之外,依賴扁平化還引入了新的問題寥院。

不確定性

第一個(gè)問題就是不確定性劲赠。

假如A依賴于C@1.0.0, B依賴于C@2.0.0。那么依賴安裝會(huì)提升的是C@1.0.0還是C@2.0.0呢?也就是下面這兩種結(jié)構(gòu):

node_modules
├─ A
│─ C@1.0.0
├─ B
│  └─ node_modules
└─    └─ C@2.0.0

還是

node_modules
├─ A
│  └─ node_modules
│     └─ C@1.0.0
├─ B
└─ C@2.0.0

網(wǎng)上大部分說法是會(huì)根據(jù) package.json 里面的順序決定誰會(huì)被提升凛澎,放在前面的包依賴的內(nèi)容會(huì)被優(yōu)先提升霹肝。

看了下最新版本的 npm 源碼,發(fā)現(xiàn) npm 其實(shí)會(huì)先調(diào)用 localeCompare 來對(duì)依賴進(jìn)行排序塑煎,也就是字典序在前面的包依賴的內(nèi)容會(huì)被優(yōu)先提升沫换。這樣即使修改package.json里依賴的順序,也不會(huì)影響依賴提升最铁,解決了不確定性讯赏。

幽靈依賴

第二個(gè)問題就是幽靈依賴。

package.json中不存在卻可以直接使用的依賴就是幽靈依賴冷尉。 在依賴扁平化后漱挎,被提升的依賴就是幽靈依賴。

假如A依賴于C@1.0.0雀哨。

node_modules
├─ A
└─ C@1.0.0

C@1.0.0就是幽靈依賴磕谅。我們可以在項(xiàng)目中直接使用C@1.0.0,但是package.json中并沒有這個(gè)依賴項(xiàng)。

這看上去好像沒什么問題雾棺,但是設(shè)想這種情況:有人發(fā)現(xiàn)依賴 A 不再使用怜庸,于是刪除了 A。但是幽靈依賴C@1.0.0依然在項(xiàng)目被使用著垢村,這就會(huì)引起報(bào)錯(cuò)割疾。

pnpm 的破局之法

pnpm 的出現(xiàn)解決了分身依賴幽靈依賴的問題。那 pnpm 是如何解決的呢嘉栓?

假如 A 依賴于 C@1.0.0宏榕,那么通過 pnpm 安裝后的依賴目錄如下:

node_modules
├─ .pnpm
│  └─ node_modules // 非直接依賴的包, 都是符號(hào)連接
│
│  └─ A@1.0.0
│     └─ node_modules
│        └─ A -> <store>/A
│        └─ C -> ../../C@1.0.0/node_modules/C
│
│  └─ C@1.0.0
│     └─ node_modules
│        └─ C -> <store>/C
│
└─ A  -> ./.pnpm/A@1.0.0/node_modules/A

node_modules 根目錄下有一個(gè) .pnpm文件夾和 A。這里的 A 是個(gè)軟連接侵佃,指向它的硬連接麻昼。

可以簡單理解為:

硬連接是指向?qū)嶋H存儲(chǔ)位置的一個(gè)指針文件。

軟連接是指向硬連接的一個(gè)指針文件馋辈。

所有的依賴都會(huì)在 .pnpm 文件夾羅列出來(不同版本可以看做是不同的依賴)抚芦。每個(gè)依賴有個(gè) node_modules 文件夾,里面存放的是自身的硬連接和自身所依賴的依賴的軟連接迈螟。

用圖片來表示如下:

link.jpg

這樣 pnpm 就保證了同一個(gè)版本的依賴只安裝一份叉抡。依賴根目錄存放的是所有的直接依賴的軟連接。至于依賴之間的關(guān)系則同樣是通過軟連接來構(gòu)建答毫。

lock 文件

npm 的 package-lock.json褥民,yarn 的 yarn.lock,以及 pnpm 的 pnpm-lock.yaml 都是 lock 文件洗搂,用于鎖定依賴項(xiàng)的版本和下載源贪嫂。

如果項(xiàng)目里存在 lock 文件,則安裝依賴時(shí)候會(huì)按照 lock 文件里的版本安裝灭忠。如果不存在,則會(huì)按照 package.json 里的版本安裝贞岭,且根據(jù)你所安裝的依賴生成一份 lock 文件。

很多人傾向于直接寫死 package.json 里的版本。但是 package.json 里只能鎖定直接依賴的版本,不能保證依賴的依賴版本不變逞刷。

lock 文件不僅能夠鎖定直接依賴版本還能鎖定依賴的依賴版本。 個(gè)人比較建議上傳 lock 文件到 git译隘,這樣能夠保證團(tuán)隊(duì)的依賴一致。

參考文檔

淺談 NPM 怎樣處理處理依賴和沖突

?? 聊聊依賴管理

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末洛心,一起剝皮案震驚了整個(gè)濱河市固耘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌词身,老刑警劉巖厅目,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異法严,居然都是意外死亡损敷,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門深啤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拗馒,“玉大人,你說我怎么就攤上這事溯街∮展穑” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵呈昔,是天一觀的道長挥等。 經(jīng)常有香客問我,道長堤尾,這世上最難降的妖魔是什么肝劲? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮郭宝,結(jié)果婚禮上辞槐,老公的妹妹穿的比我還像新娘。我一直安慰自己粘室,他們只是感情好催蝗,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著育特,像睡著了一般丙号。 火紅的嫁衣襯著肌膚如雪先朦。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天犬缨,我揣著相機(jī)與錄音喳魏,去河邊找鬼。 笑死怀薛,一個(gè)胖子當(dāng)著我的面吹牛刺彩,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播枝恋,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼创倔,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了焚碌?” 一聲冷哼從身側(cè)響起畦攘,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎十电,沒想到半個(gè)月后知押,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鹃骂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年台盯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片畏线。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡静盅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出寝殴,到底是詐尸還是另有隱情温亲,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布杯矩,位于F島的核電站栈虚,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏史隆。R本人自食惡果不足惜魂务,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望泌射。 院中可真熱鬧粘姜,春花似錦、人聲如沸熔酷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拒秘。三九已至号显,卻和暖如春臭猜,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背押蚤。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工蔑歌, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人揽碘。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓次屠,卻偏偏與公主長得像,于是被迫代替她去往敵國和親雳刺。 傳聞我的和親對(duì)象是個(gè)殘疾皇子劫灶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • npm的發(fā)展 最早期的npm 早期的npm的依賴會(huì)被嵌套安裝本昏,也就是說: 如果我A,B,C三個(gè)包均引用了D包,但是...
    470d98b91bd3閱讀 10,954評(píng)論 0 2
  • 1.npm是Node官方提供的包管理工具滞详,他已經(jīng)成了Node包的標(biāo)準(zhǔn)發(fā)布平臺(tái)凛俱,用于Node包的發(fā)布紊馏、傳播料饥、依賴控制...
    shuo_fd6c閱讀 2,551評(píng)論 0 0
  • 今天碰到了一些NPM相關(guān)的問題, 花了些時(shí)間搞清楚, 記錄一下. 關(guān)于NPM包依賴的扁平化 (flatten) 接...
    柳正來閱讀 2,672評(píng)論 1 1
  • 文章轉(zhuǎn)自HulkShen npm在前端開發(fā)流程中提供了非常完善的自動(dòng)化工具鏈,已成為每個(gè)前端開發(fā)者必備的工具朱监,但是...
    秋楓殘紅閱讀 633評(píng)論 0 1
  • 本文作者對(duì)比了當(dāng)前主流的包管理工具npm赫编、yarn巡蘸、pnpm之間的區(qū)別,并提出了合適的使用建議擂送,以下為譯文: NP...
    Bryan_Dong閱讀 1,076評(píng)論 0 3