【NPM】674- Npm 依賴處理的進(jìn)化史

作者:aprilandjan
來(lái)源:http://aprilandjan.github.io/
依賴地獄
早期版本的的 npm (v2) 管理模塊依賴的方式并不復(fù)雜。它讀取每個(gè)模塊的依賴列表,并下載匹配版本的依賴模塊到該模塊目錄內(nèi)的?node_modules?文件夾下;如果該依賴又依賴了其他的模塊,會(huì)繼續(xù)下載該依賴的依賴到該模塊目錄的?node_modules?文件夾下——如此遞歸執(zhí)行下去,最終形成一顆龐大的依賴樹。
例如,當(dāng)前項(xiàng)目有依賴的模塊?A,?B,?A?又依賴于模塊?C,?D,?B?又依賴于模塊?C,?E,此時(shí),項(xiàng)目的?node_modules?目錄結(jié)構(gòu)如下:
root
└── node_modules
├── A
│ └── node_modules
│ ├── C
│ └── D
└── B
└── node_modules
├── C
└── E
可以想象,這樣做的確能盡量保證每個(gè)模塊自身的可用性。但是,當(dāng)項(xiàng)目規(guī)模達(dá)到一定程度時(shí),也會(huì)造成許多問(wèn)題:
依賴樹的層級(jí)非常深。如果需要定位某依賴的依賴,很難找到該依賴的文件所在(例如,如果想定位模塊? E,就不得不先知道他在依賴樹中的位置);不同的依賴樹分支里,可能有大量實(shí)際上是同樣版本的依賴(例如, A?目錄下的?C?和?B?目錄下面的?C?如果版本一致,實(shí)際上完全一樣);安裝時(shí)額外下載或拷貝了大量重復(fù)的資源,并且實(shí)際上也占用了大量的硬盤空間資源等(例如, C?模塊在依賴目錄中出現(xiàn)了兩次);安裝速度慢,甚至因?yàn)槟夸泴蛹?jí)太深導(dǎo)致文件路徑太長(zhǎng)的緣故,在 windows 系統(tǒng)下刪除? node_modules?文件夾也可能失敗!
正是因?yàn)檫@些問(wèn)題的存在,彼時(shí)的?node_modules?又被叫做依賴地獄(Dependency Hell)。
依賴共享與沖突
在 npm v3 版本之后,npm 采用了更合理的方式去解決之前的依賴地域的問(wèn)題。npm v3 嘗試把依賴以及依賴的依賴都盡量的平鋪在項(xiàng)目根目錄下的?node_modules?文件夾下以共享使用;如果遇到因?yàn)樾枰陌姹疽蟛灰恢聦?dǎo)致沖突,沒辦法放在平鋪目錄下的,回退到 npm v2 的處理方式,在該模塊下的?node_modules?里存放沖突的模塊。
例如,當(dāng)前項(xiàng)目有依賴的模塊?[email protected],?[email protected],?[email protected]?依賴于模塊?[email protected],?[email protected],?[email protected]?又依賴于模塊?[email protected],?[email protected]。注意,此時(shí)由于模塊?C?的兩個(gè)版本?[email protected]?和?[email protected]?被分別依賴,鑒于模塊在同一個(gè)?node_modules?目錄中是按照模塊名目錄存放,因此這兩個(gè)版本沒辦法同時(shí)平鋪在同一目錄,因此,其中一個(gè)版本的?C?模塊將會(huì)以 npm v2 的處理方式放入子?node_modules?目錄中。
那么,應(yīng)該是哪一個(gè)版本的?C?會(huì)被這樣處理呢?考慮以下操作時(shí)序:
在空目錄下,通過(guò)? npm install \--save [email protected]?先安裝?A。由于它和它的依賴在?node_modules?下都不會(huì)產(chǎn)生沖突,因此能夠直接平鋪的放入其中。此時(shí)目錄結(jié)構(gòu)如下:
root
└── node_modules
├── [email protected]
├── [email protected]
└── [email protected]
繼續(xù)通過(guò)? npm install \--save [email protected]?安裝?B。B?自身以及它的依賴?E?也沒有沖突,直接平鋪放入?node_modules?下;但是?B?的另一依賴?[email protected]?因?yàn)?[email protected]?已經(jīng)存在了,出現(xiàn)了版本沖突,它將不得不被放置于?B?目錄下的?node_modules?中。此時(shí)目錄結(jié)構(gòu)如下:
root
└── node_modules
├── [email protected]
├── [email protected]
│ └── node_modules
│ └── [email protected]
├── [email protected]
├── [email protected]
└── [email protected]
通過(guò)以上分析可知,如果先安裝?B?再安裝?A,[email protected]?將位于?A?目錄下的?node_modules?中。這說(shuō)明:模塊的安裝順序可能影響?node_modules?內(nèi)的文件結(jié)構(gòu)。
在上面的先? A?后?B?的情形下,繼續(xù)安裝依賴?[email protected],它擁有依賴?[email protected]?和?[email protected]。類似的,它的依賴?[email protected]?因?yàn)榘姹緵_突,不得不被放置于?F?的?node_modules中。此時(shí)目錄結(jié)構(gòu)如下:
root
└── node_modules
├── [email protected]
├── [email protected]
│ └── node_modules
│ └── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
└── [email protected]
└── node_modules
└── [email protected]
觀察發(fā)現(xiàn),模塊?[email protected]?還是出現(xiàn)了冗余。然而,假如安裝的順序是?B?A?F,可以想象,將不會(huì)出現(xiàn)模塊冗余的情況。這說(shuō)明:模塊安裝順序可能影響?node_modules?內(nèi)的文件數(shù)量。
假設(shè)模塊?
A?的新版本?[email protected],它不再依賴?[email protected]?而是?[email protected], 現(xiàn)在在以上項(xiàng)目中執(zhí)行?npm install A@2,將會(huì)發(fā)生以下操作:此時(shí)的目錄結(jié)構(gòu)如下:
移除模塊? [email protected];移除模塊? [email protected],因?yàn)闆]有其他的模塊依賴它;添加模塊? [email protected];在頂層? node_modules?中安裝模塊?[email protected],因?yàn)轫攲幽夸浿袥]有版本沖突發(fā)生。
root
└── node_modules
├── [email protected]
├── [email protected]
│ └── node_modules
│ └── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
└── [email protected]
└── node_modules
└── [email protected]
可以發(fā)現(xiàn),目錄中冗余了多個(gè)?[email protected]?模塊!所幸 npm 提供了一個(gè)單獨(dú)的命令?npm dedupe用以去掉類似情況下產(chǎn)生的冗余拷貝。在 dedupe 之后,目錄結(jié)構(gòu)如下:
root
└── node_modules
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
└── [email protected]
順便提一句:yarn?在安裝依賴時(shí)會(huì)自動(dòng)執(zhí)行?dedupe?操作:
$ yarn dedupe
yarn dedupe v1.17.3
error The dedupe command isn't necessary. `yarn install` will already dedupe.
info Visit https://yarnpkg.com/en/docs/cli/dedupe for documentation about this command.
可見 yarn 在設(shè)計(jì)時(shí)的確是抓住了很多細(xì)小的點(diǎn)去改善使用體驗(yàn)。
參考
https://npm.github.io/how-npm-works-docs/index.html

回復(fù)“加群”與大佬們一起交流學(xué)習(xí)~
點(diǎn)擊“閱讀原文”查看70+篇原創(chuàng)文章

