探討npm依賴管理之peerDependencies
引言
想必前端同學對npm的devDependencies和dependencies都比較熟悉,但是對peerDependencies可能就有點陌生,尤其是沒有寫過npm包外掛的同學,比如之前使用grunt自動化工具的相關外掛(如grunt-contrib-jasmine等)或者目前基於某個框架的ui元件庫等等,這些都是需要對peerDependencies有一定了解的。下面我們就來說說peerDependencies。
npm2中dependencies與peerDependencies區別
假設我們當前的專案是MyProject,專案中有一些依賴,比方其中有一個依賴包 PackageA ,該包的 package.json 檔案指定了對 PackageB 的依賴:
{ "dependencies": { "PackageB": "1.0.0" } }
如果我們在我們的MyProject專案中執行 npm install PackageA
, 我們會發現我們專案的目錄結構會是如下形式:
MyProject |- node_modules |- PackageA |- node_modules |- PackageB
那麼在我們的專案中,我們能通過下面語句引入"PackageA":
var packageA = require('PackageA')
但是,如果你想在專案中直接引用PackageB:
var packageA = require('PackageA') var packageB = require('PackageB')
這是不行的,即使PackageB被安裝過;因為Node只會在“MyProject/node_modules”目錄下查詢PackageB,它不會在進入PackageA模組下的node_modules下查詢。
所以,為了解決這個問題,在MyProject專案package.json中我們必須直接宣告對PackageB的依賴並安裝。
但是,有時我們不用在當前專案中宣告對PackageB的依賴就可以直接引用,尤其是,PackageA是一個類似於 grunt 的外掛,例如grunt-contrib-jshint。
為什麼在專案中不用宣告就可以直接使用呢?這就不得不說說peerDependencies的作用了。
peerDependencies的引入
為了解決這種問題:
如果你安裝我,那麼你最好也安裝X,Y和Z.
於是 peerDependencies
就被引入了。例如上面PackageA的 package.json 檔案如果是下面這樣:
{ "peerDependencies": { "PackageB": "1.0.0" } }
那麼,它會告訴npm:如果某個package把我列為依賴的話,那麼那個package也必需應該有對PackageB的依賴。
也就是說,如果你 npm install PackageA
,你將會得到下面的如下的目錄結構:
MyProject |- node_modules |- PackageA |- PackageB
你可能注意到:
在npm2中,即使當前專案MyProject中沒有直接依賴PackageB,該PackageB包依然會安裝到當前專案的node_modules資料夾中。
下面的程式碼現在可以正常工作了,因為兩個包在"MyProject/node_modules"中被安裝了:
var packageA = require('PackageA') var packageB = require('PackageB')
總結一句話, peerDependencies
的具體作用:
peerDependencies
的目的是提示宿主環境去安裝滿足外掛peerDependencies所指定依賴的包,然後在外掛import或者require所依賴的包的時候,永遠都是引用宿主環境統一安裝的npm包,最終解決外掛與所依賴包不一致的問題。
舉個例子,就拿目前基於react的ui元件庫 [email protected] 來說,因該ui元件庫只是提供一套react元件庫,它要求宿主環境需要安裝指定的react版本。具體可以看它 ofollow,noindex" target="_blank">package.json 中的配置:
"peerDependencies": { "react": ">=16.0.0", "react-dom": ">=16.0.0" }
它要求宿主環境安裝react@>=16.0.0和react-dom@>=16.0.0的版本,而在每個antd元件的定義檔案頂部:
import * as React from 'react'; import * as ReactDOM from 'react-dom';
元件中引入的react和react-dom包其實都是宿主環境提供的依賴包。
npm2和npm3中peerDependencies的區別
正如上一節談論的,在npm2中,PackageA包中 peerDependencies
所指定的依賴會隨著 npm install PackageA
一起被強制安裝,所以不需要在宿主環境的package.json檔案中指定對PackageA中 peerDependencies
內容的依賴。
但是在npm3中, peerDependencies
的表現與npm2不同:
npm3中不會再要求peerDependencies所指定的依賴包被強制安裝,相反npm3會在安裝結束後檢查本次安裝是否正確,如果不正確會給使用者列印警告提示。
就拿上面的例子來說,如果我們npm install PackageA安裝PackageA時,你會得到一個警告提示說:
PackageB是一個需要的依賴,但是沒有被安裝。
這時,你需要手動的在MyProject專案的package.json檔案指定PackageB的依賴。
另外,在npm3的專案中,可能存在一個問題就是你所依賴的一個package包更新了它peerDependencies的版本,那麼你可能也需要在專案的package.json檔案中手動更新到正確的版本。否則會出現類似下圖所示的警告資訊:
參考
3、 Dealing with the deprecation of peerDependencies in NPM 3