1. 程式人生 > >詳解npm的模塊安裝機制

詳解npm的模塊安裝機制

追加 all 這樣的 2.0 https alt png wid 解釋

詳解npm的模塊安裝機制

依賴樹表面的邏輯結構與依賴樹真實的物理結構

依賴樹表面的邏輯結構與依賴樹真實的物理結構並不一定相同! 這裏要先提到兩個命令:tree -d(linux)和npm ls(npm) 在一個npm項目下: tree -d命令以樹狀圖的方式列出一個項目下所有依賴的物理結構 npm ls命令以樹狀圖的方式列出一個項目下所有依賴的邏輯結構 以官方文檔為例子: 項目example1有兩個依賴模塊:mod-a模塊和mod-c模塊; mod-a模塊有一個依賴模塊[email protected]模塊 mod-c模塊有一個依賴模塊[email protected]模塊 tree -d 和npm ls運行結果如下:(註意npm版本為npm3而非npm2) 技術分享圖片
先看看下面那個紅框的結果,這應該是“最符合我們理解”的依賴樹,首先項目下形成了一級依賴——mod-a模塊和mod-b模塊,然後以這兩個模塊為父模塊再追加二級依賴模塊[email protected][email protected] 但是!這卻並不是物理上真實形成的依賴樹的模樣,物理上真實形成的依賴樹是上面的那個紅色框。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 ):https://docs.npmjs.com/how-npm-works/packages 【溫馨提醒】:任何一篇膾炙人口的博客,都比不上一本厚重的書籍和枯燥的文檔 【完】

詳解npm的模塊安裝機制