依賴樹表面的邏輯結構與依賴樹真實的物理結構
依賴樹表面的邏輯結構與依賴樹真實的物理結構不一定相同!
這裡要先提到兩個指令:tree -d(linux)和npm ls(npm)
在一個npm專案下:
tree -d指令以樹狀圖的方式列出一個項目下所有依賴的物理結構
#npm ls指令以樹狀圖的方式列出一個項目下所有依賴的邏輯結構
以官方文件為範例:
專案example1有兩個依賴模組:mod-a模組和mod-c模組;
mod-a模組有一個依賴模組mod-b@1.0.0模組
#mod-c模組有一個依賴模組mod-b@2.0.0模組
tree -d 和npm ls運行結果如下:(注意npm版本為npm3而非npm2)
#先看看下面那個紅框的結果,這應該是「最符合我們理解」的依賴樹,首先項目下形成了一級依賴-mod-a模組和mod-b模組,然後以這兩個模組為父模組再追加二級依賴模組mod-b@1.0 .0和mod-b@2.0.0
但是! 這並不是物理上真實形成的依賴樹的模樣,物理上真實形成的依賴樹是上面的那個紅色框。 mod-a,mod-c和mod-b竟然同為同一級的依賴。
你可能會問,為什麼會形成這樣的依賴樹呢? 下面我就來解釋一番
#【注意】:下面的圖示全部為依賴樹的物理結構,而不是邏輯結構
#關於npm模組安裝機制的一點猜想
安裝模組時,可能的方式有兩種:平級式的安裝或嵌套式的安裝(這裡只是猜想和假設)
#能不能完全採取平階的安裝方式呢? ——不能
我們取和上面相似的一個例子:專案APP下有兩個依賴模組A和B;A又有一個依賴模組Cv1.0;而B也有一個依賴模組Cv2.0。顯然,它們並不能同時存在於同一個node_modules下,當安裝的時候,由於npm的作用機制,只能有一個版本的依賴模組被安裝,其中一個將覆蓋另外一個。
但如果我們只安裝一個版本的C依賴模組,將可能會導致A模組和B模組不相容
#
基於上述原因,npm2選擇了嵌套的安裝方式-
#npm2下的模組安裝機制
npm2安裝多層次的依賴模組採用巢狀的安裝方式:
#
##
優點與缺點
優點:
解決了版本單一時存在的存在的不相容問題,
實現多版本相容
#弊端:可能造成相同模組大量冗餘
的問題,如下:
以上面例子為例,下面這種情況也是合理存在的:
#憑感覺也知道,這絕不是什麼好現象,那我們如何在實現依賴間多版本相容的前提下,減少這種模組冗餘呢?於是npm3做了改進
#npm3下的模組安裝機制:
npm3和npm2的不同主要體現在二級模組的安裝上:#npm3會"盡量"##把邏輯上某個層級的模組在物理結構上"全部"放在專案的第一層級裡,具體我概括為以下三種情況:
# 1.在安裝某個二級模組時,若發現第一##等級還沒有相同名稱的模組,便
把這第二層級的模組放在第一層級
2.在安裝某個二級模組時,若發現第一層級有相同名稱,相同版本的模組,便
直接重複使用那個模組###############3.在安裝某個二級模組時,若發現第######一#####層級### ###有相同名稱,但版本不同的模組######,便###只能嵌套在自身的父模組下方#########
這開始可能有些難理解,所以讓我們看圖片說話吧!
#先說1:安裝某個二級模組時,若發現第一層級還沒有相同名稱的模組,便把這第二層級的模組放在第一層級
我們先簡化一下上面的範例:現在專案APP下只有一個一級依賴模組A,它下面有一個二級依賴模組C,但npm install的時候,項目下安裝依賴的
npm3中的二級模組(C v1.0),在專案的一級目錄(node_modules)下沒有相同名稱的模組時,會被安裝到一級目錄下,從而跟它的父模組A同級。 這就是本文一開始依賴樹的邏輯結構和物理結構不同的起因。
也就是說:
在npm2中,依賴樹的邏輯結構和它的物理結構相同
#在npm3中,依賴樹的邏輯結構和它的物理結構可能不同
#再說2:在安裝某個二級模組時,若發現第一層級有相同名稱,相同版本的模組,便直接重複使用那個模組
#
在1的基礎上,我們把1的例子還原回之前的複雜一些的場景::專案APP下有兩個依賴模組A和B;A又有一個依賴模組Cv1.0;而B也有一個依賴模組C v1.0(兩個C模組版本相同)
#對npm2,兩個C套件是相同的,造成模組冗餘
在npm3中,因為A模組下的C模組被安裝到了第一級,這使得B模組能夠復用處在同一級下;且名稱,版本,均相同的C模組
npm3就是用這種方式,部分地解決了npm2的痛點(部分)
【從1,2到3的過渡】我在這一小節的開始說:「npm3會」盡量」把邏輯上某個層級的模組"全部"放在專案的第一層級」,我想你看完1,2後應該多少有些理解了「盡量」的含義了,但我說了「盡量」,也意味著npm3存在著不能把二級依賴放在第一層級的情況。對此,請看3:
#最後說3:在安裝某個二級模組時,若發現第一層層級有相同名稱,但版本不同的模組,只能嵌套在自身的父模組下方
#
在2中,A,B所依賴的兩個C模組是相同的,但如果兩個C模組的版本不同呢? ,項目npm install情況如下:
在npm3中,因為B和A所要求的依賴模組不同,(B下要求是v1.0的C,A下要求是v2.0的C )所以B不能像2中那樣複用A下的C v1.0模組
(看到這裡我想應該能解答你對文章開頭那個例子的疑惑了吧,這個例子和那個例子是幾乎完全一樣的哦)
#
看到這裡,你對npm2和npm3下的模組工作機制,以及npm3針對npm2的優化有個大體的了解了吧,但請思考一個問題:npm3是否已經把npm2的模組冗餘的缺陷優化到極致了呢? ———答案是沒有,請往下看:
##實際上:npm3中仍然可能出現模組冗餘的情況,因為一級目錄下已經有v1.0的C模組了,所以所有的v2.0只能作為二級依賴模組被安裝
,這樣你就會看到如下的情況
##
並且在上圖所示的這種特殊情況裡,npm3和npm2表現得似乎並沒什麼區別
#
【過渡】那麼這有沒有解決的方式呢?當然是有的,當A模組下的C v1.0模組被更新到C v2.0的前提下,我們可以透過npm dedupe把所有C v2.0的二級依賴模組「重定向」到一級目錄下的那個C v1.0
#利用npm dedupe去除冗餘模組:
#npm dedupe做了什麼? 它能夠把凡是能夠去除的冗餘的二級依賴模組,「重定向」到名稱/版本相同的一級模組
參考資料 npm官方文件第二節(how npm works ):
##【溫馨提醒】:任何一篇膾炙人口的博客,都比不上一本厚重的書籍和枯燥的文檔
【完】
#每天記10個小單字吧,重在累積哦!
memory:記憶體 Dependency:依賴 constraints:約束deploy:部署parameter:參數scope:作用域
#ecosystems:生態系統prefix:前綴Prior:優先/之前 revoke:撤銷
####
##
以上是npm的模組安裝機制詳細介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!